mirror of
https://github.com/GAM-team/GAM.git
synced 2026-07-03 20:31:35 +00:00
Added use_classroom_owner_access Boolean variable to gam.cfg
This commit is contained in:
@@ -3,9 +3,10 @@
|
|||||||
- [Notes](#notes)
|
- [Notes](#notes)
|
||||||
- [Definitions](#definitions)
|
- [Definitions](#definitions)
|
||||||
- [Create classroom invitations](#create-classroom-invitations)
|
- [Create classroom invitations](#create-classroom-invitations)
|
||||||
- [Accept classroom invitations](#accept-classroom-invitations)
|
- [Accept classroom invitations by user](#accept-classroom-invitations-by-user)
|
||||||
- [Delete classroom invitations](#delete-classroom-invitations)
|
- [Delete classroom invitations by user](#delete-classroom-invitations-by-user)
|
||||||
- [Display classroom invitations by user](#display-classroom-invitations-by-user)
|
- [Display classroom invitations by user](#display-classroom-invitations-by-user)
|
||||||
|
- [Delete classroom invitations by course](#delete-classroom-invitations-by-course)
|
||||||
- [Display classroom invitations by course](#display-classroom-invitations-by-course)
|
- [Display classroom invitations by course](#display-classroom-invitations-by-course)
|
||||||
|
|
||||||
## API documentation
|
## API documentation
|
||||||
@@ -24,8 +25,6 @@ Scope: https://www.googleapis.com/auth/classroom.rosters , Checked: FA
|
|||||||
```
|
```
|
||||||
Follow the directions to authorize the Service Account scopes.
|
Follow the directions to authorize the Service Account scopes.
|
||||||
|
|
||||||
The Classroom API does not support inviting users from outside your domain.
|
|
||||||
|
|
||||||
## Definitions
|
## Definitions
|
||||||
```
|
```
|
||||||
<DomainName> ::= <String>(.<String>)+
|
<DomainName> ::= <String>(.<String>)+
|
||||||
@@ -49,12 +48,18 @@ The Classroom API does not support inviting users from outside your domain.
|
|||||||
Invite users to classes.
|
Invite users to classes.
|
||||||
```
|
```
|
||||||
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
|
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
|
||||||
[adminaccess|asadmin] [csvformat] [todrive <ToDriveAttributes>*] [formatjson [quotechar <Character>]]
|
[adminaccess|asadmin]
|
||||||
|
[csv|csvformat] [todrive <ToDriveAttributes>*] [formatjson [quotechar <Character>]]
|
||||||
```
|
```
|
||||||
If `role` is not specified, `student` will be used.
|
If `role` is not specified, `student` will be used.
|
||||||
|
|
||||||
|
You can only invite a co-teacher to be an owner of a course.
|
||||||
|
|
||||||
By default, classroom invitations are issued by the owner of the course, the `adminaccess` option causes the invitations to be issued by the admin named in `oauth2.txt`.
|
By default, classroom invitations are issued by the owner of the course, the `adminaccess` option causes the invitations to be issued by the admin named in `oauth2.txt`.
|
||||||
|
|
||||||
|
By default, when an invitation is created, GAM outputs details of the invitation as indented keywords and values.
|
||||||
|
* `csv|csvformat [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]` - Output the details in CSV format.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
Suppose you have a CSV file CourseStudent.csv with two columns: Course,Student.
|
Suppose you have a CSV file CourseStudent.csv with two columns: Course,Student.
|
||||||
@@ -66,11 +71,13 @@ This command will invite all students to their courses in parallel
|
|||||||
```
|
```
|
||||||
gam redirect stdout ./Invites.out multiprocess redirect stderr stdout multiprocess csv CourseStudent.csv gam user ~Student create classroominvitation role student course ~Course
|
gam redirect stdout ./Invites.out multiprocess redirect stderr stdout multiprocess csv CourseStudent.csv gam user ~Student create classroominvitation role student course ~Course
|
||||||
```
|
```
|
||||||
## Accept classroom invitations
|
## Accept classroom invitations by user
|
||||||
Accept classroom invitations for users. You can only invite a co-teacher to be an owner of a course.
|
Accept classroom invitations for users.
|
||||||
```
|
```
|
||||||
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
||||||
```
|
```
|
||||||
|
`<UserTypeEntity>` must specify users in your domain.
|
||||||
|
|
||||||
By default, all invitations for the specified users will be accepted.
|
By default, all invitations for the specified users will be accepted.
|
||||||
|
|
||||||
Select specific invitations to accept:
|
Select specific invitations to accept:
|
||||||
@@ -81,11 +88,13 @@ Select courses and accept invitations for those courses.
|
|||||||
|
|
||||||
By default, invitations for all roles will be accepted; you can limit the acceptances to invitations of a specific role.
|
By default, invitations for all roles will be accepted; you can limit the acceptances to invitations of a specific role.
|
||||||
|
|
||||||
## Delete classroom invitations
|
## Delete classroom invitations by user
|
||||||
Delete classroom invitations for users.
|
Delete classroom invitations for users.
|
||||||
```
|
```
|
||||||
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
||||||
```
|
```
|
||||||
|
`<UserTypeEntity>` must specify users in your domain.
|
||||||
|
|
||||||
By default, all invitations for the specified users will be deleted.
|
By default, all invitations for the specified users will be deleted.
|
||||||
|
|
||||||
Select specific invitations to delete:
|
Select specific invitations to delete:
|
||||||
@@ -104,8 +113,23 @@ gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
|
|||||||
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttributes>*] [role all|owner|student|teacher]
|
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttributes>*] [role all|owner|student|teacher]
|
||||||
[formatjson [quotechar <Character>]]
|
[formatjson [quotechar <Character>]]
|
||||||
```
|
```
|
||||||
|
`<UserTypeEntity>` must specify users in your domain.
|
||||||
|
|
||||||
By default, invitations for all roles will be displayed; you can limit the display to invitations of a specific role.
|
By default, invitations for all roles will be displayed; you can limit the display to invitations of a specific role.
|
||||||
|
|
||||||
|
## Delete classroom invitations by course
|
||||||
|
Delete classroom invitations for courses. This command must be used to delete non-domain member invitations.
|
||||||
|
```
|
||||||
|
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
|
||||||
|
```
|
||||||
|
Select courses and delete invitations for those courses.
|
||||||
|
* `courses <CourseEntity>` - Specify courses
|
||||||
|
|
||||||
|
Select specific invitations to delete:
|
||||||
|
* `ids <ClassroomInvitationIDEntity>` - Specify invitation IDs
|
||||||
|
|
||||||
|
Select invitations to delete by role. By default, invitations for all roles will be deleted; you can limit the deletions to invitations of a specific role.
|
||||||
|
|
||||||
## Display classroom invitations by course
|
## Display classroom invitations by course
|
||||||
```
|
```
|
||||||
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
|
|||||||
@@ -48,10 +48,7 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
|
|||||||
## Display File Ownership for Old files
|
## Display File Ownership for Old files
|
||||||
If the above commands fail, you can try to loop through all accounts, however this might take a long time if you are on a large Google Workspace Account.
|
If the above commands fail, you can try to loop through all accounts, however this might take a long time if you are on a large Google Workspace Account.
|
||||||
|
|
||||||
```
|
|
||||||
gam config auto_batch_min 1 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
|
|
||||||
```
|
|
||||||
Starting with version 6.07.26, this can be made more efficient by terminating processing after the owner is identified.
|
|
||||||
```
|
```
|
||||||
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
|
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
|
||||||
|
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select name <DriveFileName> fields id,name,owners.emailaddress norecursion showownedby any
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,6 +10,26 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
|||||||
|
|
||||||
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
|
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
|
||||||
|
|
||||||
|
### 6.69.00
|
||||||
|
|
||||||
|
Added `use_classroom_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
|
||||||
|
classroom member information and removes students/teachers. Client access does not provide
|
||||||
|
complete information about non-domain students/teachers.
|
||||||
|
* `False` - Use client access; this is the default. Use if you don't have non-domain members in your courses.
|
||||||
|
* `True` - Use service account access as the classroom owner. An extra API call is required per course to authenticate the owner; this will affect performance
|
||||||
|
|
||||||
|
Added the following command which must be used to delete classroom invitations for non-domain students/teachers.
|
||||||
|
```
|
||||||
|
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
|
||||||
|
```
|
||||||
|
You can obtain the classroom invitation IDs with these commands:
|
||||||
|
```
|
||||||
|
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
|
[role all|owner|student|teacher] [formatjson]
|
||||||
|
gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
|
[role all|owner|student|teacher] [formatjson [quotechar <Character>]]
|
||||||
|
```
|
||||||
|
|
||||||
### 6.68.08
|
### 6.68.08
|
||||||
|
|
||||||
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
|
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ writes the credentials into the file oauth2.txt.
|
|||||||
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||||
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
|
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
|
||||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||||
GAMADV-XTD3 6.68.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
GAMADV-XTD3 6.69.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
MacOS Sonoma 14.2.1 x86_64
|
MacOS Sonoma 14.2.1 x86_64
|
||||||
@@ -1002,7 +1002,7 @@ writes the credentials into the file oauth2.txt.
|
|||||||
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
|
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
|
||||||
C:\GAMADV-XTD3>gam version
|
C:\GAMADV-XTD3>gam version
|
||||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||||
GAMADV-XTD3 6.68.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
GAMADV-XTD3 6.69.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
Windows-10-10.0.17134 AMD64
|
Windows-10-10.0.17134 AMD64
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ Thank you.
|
|||||||
* Goldy Arora - https://www.goldyarora.com/license-notifier/
|
* Goldy Arora - https://www.goldyarora.com/license-notifier/
|
||||||
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
|
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
|
||||||
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Course on Udemy https://taming.tech/GAMCourse
|
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Course on Udemy https://taming.tech/GAMCourse
|
||||||
|
* Paul Ogier (Taming.Tech) - https://taming.tech/taming-gam-a-practical-guide-to-gam-and-gamadv-xtd3/
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
Print the current version of Gam with details
|
Print the current version of Gam with details
|
||||||
```
|
```
|
||||||
gam version
|
gam version
|
||||||
GAMADV-XTD3 6.68.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
GAMADV-XTD3 6.69.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
MacOS Sonoma 14.2.1 x86_64
|
MacOS Sonoma 14.2.1 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
|
Print the current version of Gam with details and time offset information
|
||||||
```
|
```
|
||||||
gam version timeoffset
|
gam version timeoffset
|
||||||
GAMADV-XTD3 6.68.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
GAMADV-XTD3 6.69.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
MacOS Sonoma 14.2.1 x86_64
|
MacOS Sonoma 14.2.1 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
|
Print the current version of Gam with extended details and SSL information
|
||||||
```
|
```
|
||||||
gam version extended
|
gam version extended
|
||||||
GAMADV-XTD3 6.68.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
GAMADV-XTD3 6.69.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
MacOS Sonoma 14.2.1 x86_64
|
MacOS Sonoma 14.2.1 x86_64
|
||||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
|||||||
Path: /Users/Admin/bin/gamadv-xtd3
|
Path: /Users/Admin/bin/gamadv-xtd3
|
||||||
Version Check:
|
Version Check:
|
||||||
Current: 5.35.08
|
Current: 5.35.08
|
||||||
Latest: 6.68.08
|
Latest: 6.69.00
|
||||||
echo $?
|
echo $?
|
||||||
1
|
1
|
||||||
```
|
```
|
||||||
@@ -72,7 +72,7 @@ echo $?
|
|||||||
Print the current version number without details
|
Print the current version number without details
|
||||||
```
|
```
|
||||||
gam version simple
|
gam version simple
|
||||||
6.68.08
|
6.69.00
|
||||||
```
|
```
|
||||||
In Linux/MacOS you can do:
|
In Linux/MacOS you can do:
|
||||||
```
|
```
|
||||||
@@ -82,7 +82,7 @@ echo $VER
|
|||||||
Print the current version of Gam and address of this Wiki
|
Print the current version of Gam and address of this Wiki
|
||||||
```
|
```
|
||||||
gam help
|
gam help
|
||||||
GAM 6.68.08 - https://github.com/taers232c/GAMADV-XTD3
|
GAM 6.69.00 - https://github.com/taers232c/GAMADV-XTD3
|
||||||
Ross Scroggs <ross.scroggs@gmail.com>
|
Ross Scroggs <ross.scroggs@gmail.com>
|
||||||
Python 3.12.2 64-bit final
|
Python 3.12.2 64-bit final
|
||||||
MacOS Sonoma 14.2.1 x86_64
|
MacOS Sonoma 14.2.1 x86_64
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ csv_input_column_delimiter
|
|||||||
Default: ','
|
Default: ','
|
||||||
csv_input_no_escape_char
|
csv_input_no_escape_char
|
||||||
When reading a CSV file, should `\` be ignored as an escape character.
|
When reading a CSV file, should `\` be ignored as an escape character.
|
||||||
Set this to False if the input file data was written using `\` as an escape character.
|
Set this to False if the input file data was written using `\` as an escape character.
|
||||||
Default: True
|
Default: True
|
||||||
csv_input_quote_char
|
csv_input_quote_char
|
||||||
A one-character string used to quote fields containing special characters,
|
A one-character string used to quote fields containing special characters,
|
||||||
@@ -220,7 +220,7 @@ csv_output_line_terminator
|
|||||||
Default: lf
|
Default: lf
|
||||||
csv_output_no_escape_char
|
csv_output_no_escape_char
|
||||||
When writing a CSV file, should `\` be ignored as an escape character.
|
When writing a CSV file, should `\` be ignored as an escape character.
|
||||||
Set this to True if the output file data is to be read by a non-Python program.
|
Set this to True if the output file data is to be read by a non-Python program.
|
||||||
Default: False
|
Default: False
|
||||||
csv_output_quote_char
|
csv_output_quote_char
|
||||||
A one-character string used to quote fields containing special characters,
|
A one-character string used to quote fields containing special characters,
|
||||||
@@ -420,23 +420,23 @@ print_agu_domains
|
|||||||
gam print groups
|
gam print groups
|
||||||
gam print|show group-members
|
gam print|show group-members
|
||||||
gam print users
|
gam print users
|
||||||
This allows predefining the list of domains so they don't have to be specified in each command.
|
This allows predefining the list of domains so they don't have to be specified in each command.
|
||||||
Default: Blank
|
Default: Blank
|
||||||
print_cros_ous
|
print_cros_ous
|
||||||
A comma separated list of org unit that are used in these commands:
|
A comma separated list of org unit that are used in these commands:
|
||||||
gam print cros
|
gam print cros
|
||||||
gam print crosactivity
|
gam print crosactivity
|
||||||
This allows predefining the list of org units so they don't have to be specified in each command.
|
This allows predefining the list of org units so they don't have to be specified in each command.
|
||||||
Default: Blank
|
Default: Blank
|
||||||
print_cros_ous_and_children
|
print_cros_ous_and_children
|
||||||
A comma separated list of org unit names that are used in these commands:
|
A comma separated list of org unit names that are used in these commands:
|
||||||
gam print cros
|
gam print cros
|
||||||
gam print crosactivity
|
gam print crosactivity
|
||||||
This allows predefining the list of org units so they don't have to be specified in each command.
|
This allows predefining the list of org units so they don't have to be specified in each command.
|
||||||
Default: Blank
|
Default: Blank
|
||||||
process_wait_limit
|
process_wait_limit
|
||||||
When processing batch/CSV files, how long (in seconds) GAM should wait for all batch|csv processes to complete
|
When processing batch/CSV files, how long (in seconds) GAM should wait for all batch|csv processes to complete
|
||||||
after all have been started. If the limit is reached, GAM terminates any remaining processes.
|
after all have been started. If the limit is reached, GAM terminates any remaining processes.
|
||||||
Default: 0: no limit
|
Default: 0: no limit
|
||||||
Range: 0 - Unlimited
|
Range: 0 - Unlimited
|
||||||
quick_cros_move
|
quick_cros_move
|
||||||
@@ -573,6 +573,13 @@ update_cros_ou_with_id
|
|||||||
Set to true if you are getting the following error:
|
Set to true if you are getting the following error:
|
||||||
`400: invalidInput - Invalid Input: Inconsistent Orgunit id and path in request`
|
`400: invalidInput - Invalid Input: Inconsistent Orgunit id and path in request`
|
||||||
Default: False
|
Default: False
|
||||||
|
use_classroom_owner_access
|
||||||
|
How is classroom member information obtained and how are classroom members deleted.
|
||||||
|
Client access does not provide complete information about non-domain students/teachers.
|
||||||
|
When False, GAM uses client access to get classroom member information and to delete members
|
||||||
|
When True, GAM uses service account access as the classroom owner.
|
||||||
|
An extra API call is required per course to authenticate the owner
|
||||||
|
Default: False
|
||||||
use_projectid_as_name
|
use_projectid_as_name
|
||||||
When False, new projects have a default project name of "GAM Project"
|
When False, new projects have a default project name of "GAM Project"
|
||||||
and a default app name of "GAM".
|
and a default app name of "GAM".
|
||||||
|
|||||||
@@ -2876,7 +2876,7 @@ gam course <CourseID> delete topic <CourseTopicID>
|
|||||||
|
|
||||||
gam course <CourseID> create|add teachers [makefirstteacherowner] <UserItem>
|
gam course <CourseID> create|add teachers [makefirstteacherowner] <UserItem>
|
||||||
gam course <CourseID> create|add students <UserItem>
|
gam course <CourseID> create|add students <UserItem>
|
||||||
gam course <CourseID> delete|remove teachers|students <UserItem>
|
gam course <CourseID> delete|remove teachers|students [owneraccess] <UserItem>
|
||||||
gam course <CourseID> clear teachers|students
|
gam course <CourseID> clear teachers|students
|
||||||
gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
|
gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
|
||||||
gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
|
gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
|
||||||
@@ -2889,15 +2889,17 @@ gam courses <CourseEntity> delete topic <CourseTopicIDEntity>
|
|||||||
|
|
||||||
gam courses <CourseEntity> create|add teachers [makefirstteacherowner] <UserTypeEntity>
|
gam courses <CourseEntity> create|add teachers [makefirstteacherowner] <UserTypeEntity>
|
||||||
gam courses <CourseEntity> create|add students <UserTypeEntity>
|
gam courses <CourseEntity> create|add students <UserTypeEntity>
|
||||||
gam courses <CourseEntity> delete|remove teachers|students <UserTypeEntity>
|
gam courses <CourseEntity> delete|remove teachers|students [owneraccess] <UserTypeEntity>
|
||||||
gam courses <CourseEntity> clear teachers|students
|
gam courses <CourseEntity> clear teachers|students
|
||||||
gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
|
gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
|
||||||
gam courses <CourseEntity> sync students [addonly|removeonly] <UserTypeEntity>
|
gam courses <CourseEntity> sync students [addonly|removeonly] <UserTypeEntity>
|
||||||
|
|
||||||
gam info course <CourseID> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
|
gam info course <CourseID> [owneraccess]
|
||||||
|
[owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
|
||||||
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
|
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
|
||||||
[formatjson]
|
[formatjson]
|
||||||
gam info courses <CourseEntity> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
|
gam info courses <CourseEntity> [owneraccess]
|
||||||
|
[owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
|
||||||
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
|
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
|
||||||
[formatjson]
|
[formatjson]
|
||||||
gam print courses [todrive <ToDriveAttribute>*]
|
gam print courses [todrive <ToDriveAttribute>*]
|
||||||
@@ -3041,8 +3043,8 @@ gam print course-works [todrive <ToDriveAttribute>*]
|
|||||||
# Classroom - Invitations
|
# Classroom - Invitations
|
||||||
|
|
||||||
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
|
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
|
||||||
[adminaccess|asadmin] [csv|csvformat] [todrive <ToDriveAttribute>*]
|
[adminaccess|asadmin]
|
||||||
[formatjson [quotechar <Character>]]
|
[csv|csvformat] [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]
|
||||||
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
||||||
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
|
||||||
gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
|
gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
|
||||||
@@ -3050,6 +3052,7 @@ gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
|
|||||||
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttribute>*] [role all|owner|student|teacher]
|
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttribute>*] [role all|owner|student|teacher]
|
||||||
[formatjson [quotechar <Character>]]
|
[formatjson [quotechar <Character>]]
|
||||||
|
|
||||||
|
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
|
||||||
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
[role all|owner|student|teacher]
|
[role all|owner|student|teacher]
|
||||||
[formatjson]
|
[formatjson]
|
||||||
|
|||||||
@@ -2,6 +2,26 @@
|
|||||||
|
|
||||||
Merged GAM-Team version
|
Merged GAM-Team version
|
||||||
|
|
||||||
|
6.69.00
|
||||||
|
|
||||||
|
Added `use_classroom_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
|
||||||
|
classroom member information and removes students/teachers. Client access does not provide
|
||||||
|
complete information about non-domain students/teachers.
|
||||||
|
* `False` - Use client access; this is the default. Use if you don't have non-domain members in your courses.
|
||||||
|
* `True` - Use service account access as the classroom owner. An extra API call is required per course to authenticate the owner; this will affect performance
|
||||||
|
|
||||||
|
Added the following command which must be used to delete classroom invitations for non-domain students/teachers.
|
||||||
|
```
|
||||||
|
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
|
||||||
|
```
|
||||||
|
You can obtain the classroom invitation IDs with these commands:
|
||||||
|
```
|
||||||
|
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
|
[role all|owner|student|teacher] [formatjson]
|
||||||
|
gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
|
[role all|owner|student|teacher] [formatjson [quotechar <Character>]]
|
||||||
|
```
|
||||||
|
|
||||||
6.68.08
|
6.68.08
|
||||||
|
|
||||||
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
|
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
|
||||||
|
|||||||
@@ -3395,7 +3395,7 @@ def SetGlobalVariables():
|
|||||||
def _getCfgHeaderFilter(sectionName, itemName):
|
def _getCfgHeaderFilter(sectionName, itemName):
|
||||||
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
|
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
|
||||||
headerFilters = []
|
headerFilters = []
|
||||||
if not value:
|
if not value or (len(value) == 2 and _stringInQuotes(value)):
|
||||||
return headerFilters
|
return headerFilters
|
||||||
splitStatus, filters = shlexSplitListStatus(value)
|
splitStatus, filters = shlexSplitListStatus(value)
|
||||||
if splitStatus:
|
if splitStatus:
|
||||||
@@ -3411,7 +3411,7 @@ def SetGlobalVariables():
|
|||||||
def _getCfgHeaderForce(sectionName, itemName):
|
def _getCfgHeaderForce(sectionName, itemName):
|
||||||
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
|
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
|
||||||
headerForce = []
|
headerForce = []
|
||||||
if not value:
|
if not value or (len(value) == 2 and _stringInQuotes(value)):
|
||||||
return headerForce
|
return headerForce
|
||||||
splitStatus, headerForce = shlexSplitListStatus(value)
|
splitStatus, headerForce = shlexSplitListStatus(value)
|
||||||
if not splitStatus:
|
if not splitStatus:
|
||||||
@@ -6338,15 +6338,15 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
|
|||||||
elif entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_TEACHERS, Cmd.ENTITY_STUDENTS}:
|
elif entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_TEACHERS, Cmd.ENTITY_STUDENTS}:
|
||||||
croom = buildGAPIObject(API.CLASSROOM)
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
if not noListConversion:
|
if not noListConversion:
|
||||||
courses = convertEntityToList(entity)
|
courseIdList = convertEntityToList(entity)
|
||||||
else:
|
else:
|
||||||
courses = [entity]
|
courseIdList = [entity]
|
||||||
for course in courses:
|
_, _, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
||||||
courseId = addCourseIdScope(course)
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
try:
|
try:
|
||||||
if entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_TEACHERS}:
|
if entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_TEACHERS}:
|
||||||
printGettingAllEntityItemsForWhom(Ent.TEACHER, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
printGettingAllEntityItemsForWhom(Ent.TEACHER, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
||||||
result = callGAPIpages(croom.courses().teachers(), 'list', 'teachers',
|
result = callGAPIpages(courseInfo['croom'].courses().teachers(), 'list', 'teachers',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -6359,7 +6359,7 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
|
|||||||
entityList.append(email)
|
entityList.append(email)
|
||||||
if entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_STUDENTS}:
|
if entityType in {Cmd.ENTITY_COURSEPARTICIPANTS, Cmd.ENTITY_STUDENTS}:
|
||||||
printGettingAllEntityItemsForWhom(Ent.STUDENT, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
printGettingAllEntityItemsForWhom(Ent.STUDENT, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
||||||
result = callGAPIpages(croom.courses().students(), 'list', 'students',
|
result = callGAPIpages(courseInfo['croom'].courses().students(), 'list', 'students',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -17979,7 +17979,7 @@ def doPrintAliases():
|
|||||||
except (GAPI.invalidOrgunit, GAPI.invalidInput):
|
except (GAPI.invalidOrgunit, GAPI.invalidInput):
|
||||||
entityActionFailedWarning([Ent.ALIAS, None], invalidQuery(query))
|
entityActionFailedWarning([Ent.ALIAS, None], invalidQuery(query))
|
||||||
continue
|
continue
|
||||||
except GAPI.domainNotFound as e :
|
except GAPI.domainNotFound as e:
|
||||||
entityActionFailedWarning([Ent.ALIAS, None, Ent.DOMAIN, kwargs['domain']], str(e))
|
entityActionFailedWarning([Ent.ALIAS, None, Ent.DOMAIN, kwargs['domain']], str(e))
|
||||||
continue
|
continue
|
||||||
except (GAPI.resourceNotFound, GAPI.forbidden, GAPI.badRequest):
|
except (GAPI.resourceNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||||
@@ -18008,13 +18008,16 @@ def doPrintAliases():
|
|||||||
try:
|
try:
|
||||||
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
|
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||||
pageMessage=getPageMessage(showFirstLastItems=True), messageAttribute='email',
|
pageMessage=getPageMessage(showFirstLastItems=True), messageAttribute='email',
|
||||||
throwReasons=GAPI.GROUP_LIST_THROW_REASONS,
|
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
query=query, orderBy='email',
|
query=query, orderBy='email',
|
||||||
fields=f'nextPageToken,groups({",".join(groupFields)})', **kwargs)
|
fields=f'nextPageToken,groups({",".join(groupFields)})', **kwargs)
|
||||||
for group in entityList:
|
for group in entityList:
|
||||||
writeAliases(group, group['email'], 'Group')
|
writeAliases(group, group['email'], 'Group')
|
||||||
except GAPI.domainNotFound as e :
|
except (GAPI.invalidMember, GAPI.invalidInput) as e:
|
||||||
|
if not invalidMember(query):
|
||||||
|
entityActionFailedExit([Ent.GROUP, None], str(e))
|
||||||
|
except GAPI.domainNotFound as e:
|
||||||
entityActionFailedWarning([Ent.ALIAS, None, Ent.DOMAIN, kwargs['domain']], str(e))
|
entityActionFailedWarning([Ent.ALIAS, None, Ent.DOMAIN, kwargs['domain']], str(e))
|
||||||
continue
|
continue
|
||||||
except (GAPI.resourceNotFound, GAPI.forbidden, GAPI.badRequest):
|
except (GAPI.resourceNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||||
@@ -41517,7 +41520,7 @@ def doCreateUser():
|
|||||||
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND,
|
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND,
|
||||||
GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN,
|
GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN,
|
||||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE],
|
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.CONDITION_NOT_MET],
|
||||||
body=body,
|
body=body,
|
||||||
fields=fields,
|
fields=fields,
|
||||||
resolveConflictAccount=resolveConflictAccount)
|
resolveConflictAccount=resolveConflictAccount)
|
||||||
@@ -41536,7 +41539,7 @@ def doCreateUser():
|
|||||||
except GAPI.invalidOrgunit:
|
except GAPI.invalidOrgunit:
|
||||||
entityActionFailedExit([Ent.USER, user], Msg.INVALID_ORGUNIT)
|
entityActionFailedExit([Ent.USER, user], Msg.INVALID_ORGUNIT)
|
||||||
except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
|
except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
|
||||||
GAPI.invalid, GAPI.invalidInput, GAPI.invalidParameter) as e:
|
GAPI.invalid, GAPI.invalidInput, GAPI.invalidParameter, GAPI.conditionNotMet) as e:
|
||||||
entityActionFailedExit([Ent.USER, user], str(e))
|
entityActionFailedExit([Ent.USER, user], str(e))
|
||||||
if PwdOpts.filename and PwdOpts.password:
|
if PwdOpts.filename and PwdOpts.password:
|
||||||
writeFile(PwdOpts.filename, f'{user},{PwdOpts.password}\n', mode='a', continueOnError=True)
|
writeFile(PwdOpts.filename, f'{user},{PwdOpts.password}\n', mode='a', continueOnError=True)
|
||||||
@@ -41698,7 +41701,7 @@ def updateUsers(entityList):
|
|||||||
result = callGAPI(cd.users(), 'insert',
|
result = callGAPI(cd.users(), 'insert',
|
||||||
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.FORBIDDEN,
|
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.FORBIDDEN,
|
||||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE],
|
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.CONDITION_NOT_MET],
|
||||||
body=body,
|
body=body,
|
||||||
fields=fields,
|
fields=fields,
|
||||||
resolveConflictAccount=resolveConflictAccount)
|
resolveConflictAccount=resolveConflictAccount)
|
||||||
@@ -41730,7 +41733,7 @@ def updateUsers(entityList):
|
|||||||
entityActionFailedWarning([Ent.USER, user], Msg.INVALID_ORGUNIT, i, count)
|
entityActionFailedWarning([Ent.USER, user], Msg.INVALID_ORGUNIT, i, count)
|
||||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest,
|
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest,
|
||||||
GAPI.invalid, GAPI.invalidInput, GAPI.invalidParameter, GAPI.insufficientArchivedUserLicenses,
|
GAPI.invalid, GAPI.invalidInput, GAPI.invalidParameter, GAPI.insufficientArchivedUserLicenses,
|
||||||
GAPI.conflict, GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
|
GAPI.conflict, GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.conditionNotMet) as e:
|
||||||
entityActionFailedWarning([Ent.USER, user], str(e), i, count)
|
entityActionFailedWarning([Ent.USER, user], str(e), i, count)
|
||||||
|
|
||||||
# gam update users <UserTypeEntity> ...
|
# gam update users <UserTypeEntity> ...
|
||||||
@@ -44212,6 +44215,8 @@ class CourseAttributes():
|
|||||||
|
|
||||||
def __init__(self, croom, updateMode):
|
def __init__(self, croom, updateMode):
|
||||||
self.croom = croom
|
self.croom = croom
|
||||||
|
self.ocroom = croom
|
||||||
|
self.tcroom = None
|
||||||
self.updateMode = updateMode
|
self.updateMode = updateMode
|
||||||
self.body = {}
|
self.body = {}
|
||||||
self.courseId = None
|
self.courseId = None
|
||||||
@@ -44371,15 +44376,20 @@ class CourseAttributes():
|
|||||||
missingArgumentExit('copyfrom <CourseID>')
|
missingArgumentExit('copyfrom <CourseID>')
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
# ocroom - copyfrom course owner
|
||||||
|
if self.announcementStates or self.materialStates or self.workStates or self.copyTopics or self.members != 'none':
|
||||||
|
_, self.ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{self.ownerId}')
|
||||||
|
if self.ocroom is None:
|
||||||
|
return False
|
||||||
if self.members != 'none':
|
if self.members != 'none':
|
||||||
_, self.teachers, self.students = _getCourseAliasesMembers(self.croom, self.croom, self.courseId, {'members': self.members},
|
_, self.teachers, self.students = _getCourseAliasesMembers(self.croom, self.ocroom, self.courseId, {'members': self.members},
|
||||||
'nextPageToken,teachers(profile(emailAddress,id))',
|
'nextPageToken,teachers(profile(emailAddress,id))',
|
||||||
'nextPageToken,students(profile(emailAddress))')
|
'nextPageToken,students(profile(emailAddress))')
|
||||||
if self.announcementStates:
|
if self.announcementStates:
|
||||||
printGettingAllEntityItemsForWhom(Ent.COURSE_ANNOUNCEMENT_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
printGettingAllEntityItemsForWhom(Ent.COURSE_ANNOUNCEMENT_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
||||||
_gettingCourseEntityQuery(Ent.COURSE_ANNOUNCEMENT_STATE, self.announcementStates))
|
_gettingCourseEntityQuery(Ent.COURSE_ANNOUNCEMENT_STATE, self.announcementStates))
|
||||||
try:
|
try:
|
||||||
self.courseAnnouncements = callGAPIpages(self.croom.courses().announcements(), 'list', 'announcements',
|
self.courseAnnouncements = callGAPIpages(self.ocroom.courses().announcements(), 'list', 'announcements',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44396,7 +44406,7 @@ class CourseAttributes():
|
|||||||
printGettingAllEntityItemsForWhom(Ent.COURSE_MATERIAL_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
printGettingAllEntityItemsForWhom(Ent.COURSE_MATERIAL_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
||||||
_gettingCourseEntityQuery(Ent.COURSE_MATERIAL_STATE, self.materialStates))
|
_gettingCourseEntityQuery(Ent.COURSE_MATERIAL_STATE, self.materialStates))
|
||||||
try:
|
try:
|
||||||
self.courseMaterials = callGAPIpages(self.croom.courses().courseWorkMaterials(), 'list', 'courseWorkMaterial',
|
self.courseMaterials = callGAPIpages(self.ocroom.courses().courseWorkMaterials(), 'list', 'courseWorkMaterial',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44417,7 +44427,7 @@ class CourseAttributes():
|
|||||||
printGettingAllEntityItemsForWhom(Ent.COURSE_WORK_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
printGettingAllEntityItemsForWhom(Ent.COURSE_WORK_ID, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0,
|
||||||
_gettingCourseEntityQuery(Ent.COURSE_WORK_STATE, self.workStates))
|
_gettingCourseEntityQuery(Ent.COURSE_WORK_STATE, self.workStates))
|
||||||
try:
|
try:
|
||||||
self.courseWorks = callGAPIpages(self.croom.courses().courseWork(), 'list', 'courseWork',
|
self.courseWorks = callGAPIpages(self.ocroom.courses().courseWork(), 'list', 'courseWork',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44441,7 +44451,7 @@ class CourseAttributes():
|
|||||||
if self.copyTopics:
|
if self.copyTopics:
|
||||||
printGettingAllEntityItemsForWhom(Ent.COURSE_TOPIC, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0)
|
printGettingAllEntityItemsForWhom(Ent.COURSE_TOPIC, Ent.TypeName(Ent.COURSE, self.courseId), 0, 0)
|
||||||
try:
|
try:
|
||||||
courseTopics = callGAPIpages(self.croom.courses().topics(), 'list', 'topic',
|
courseTopics = callGAPIpages(self.ocroom.courses().topics(), 'list', 'topic',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44517,14 +44527,16 @@ class CourseAttributes():
|
|||||||
newCourseId = newCourse['id']
|
newCourseId = newCourse['id']
|
||||||
ownerId = newCourse['ownerId']
|
ownerId = newCourse['ownerId']
|
||||||
teacherFolderId = newCourse['teacherFolder']['id']
|
teacherFolderId = newCourse['teacherFolder']['id']
|
||||||
|
# tcroom - new/update course owner
|
||||||
if self.announcementStates or self.materialStates or self.workStates or self.copyTopics:
|
if self.announcementStates or self.materialStates or self.workStates or self.copyTopics:
|
||||||
_, tcroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{ownerId}')
|
_, self.tcroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{ownerId}')
|
||||||
if tcroom is None:
|
if self.tcroom is None:
|
||||||
return
|
return
|
||||||
if (self.announcementStates or self.materialStates or self.workStates) and self.copyMaterialsFiles:
|
if (self.announcementStates or self.materialStates or self.workStates) and self.copyMaterialsFiles:
|
||||||
_, tdrive = buildGAPIServiceObject(API.DRIVE3, f'uid:{ownerId}')
|
_, tdrive = buildGAPIServiceObject(API.DRIVE3, f'uid:{ownerId}')
|
||||||
if tdrive is None:
|
if tdrive is None:
|
||||||
return
|
return
|
||||||
|
# Adds are done with domain admin
|
||||||
if self.members in {'all', 'students'}:
|
if self.members in {'all', 'students'}:
|
||||||
addParticipants = [student['profile']['emailAddress'] for student in self.students if 'emailAddress' in student['profile']]
|
addParticipants = [student['profile']['emailAddress'] for student in self.students if 'emailAddress' in student['profile']]
|
||||||
_batchAddItemsToCourse(self.croom, newCourseId, i, count, addParticipants, Ent.STUDENT)
|
_batchAddItemsToCourse(self.croom, newCourseId, i, count, addParticipants, Ent.STUDENT)
|
||||||
@@ -44533,7 +44545,7 @@ class CourseAttributes():
|
|||||||
_batchAddItemsToCourse(self.croom, newCourseId, i, count, addParticipants, Ent.TEACHER)
|
_batchAddItemsToCourse(self.croom, newCourseId, i, count, addParticipants, Ent.TEACHER)
|
||||||
if self.copyTopics:
|
if self.copyTopics:
|
||||||
try:
|
try:
|
||||||
newCourseTopics = callGAPIpages(self.croom.courses().topics(), 'list', 'topic',
|
newCourseTopics = callGAPIpages(self.tcroom.courses().topics(), 'list', 'topic',
|
||||||
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.FAILED_PRECONDITION, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=GAPI.COURSE_ACCESS_THROW_REASONS+[GAPI.FAILED_PRECONDITION, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
courseId=newCourseId, fields='nextPageToken,topic(topicId,name)',
|
courseId=newCourseId, fields='nextPageToken,topic(topicId,name)',
|
||||||
@@ -44556,7 +44568,7 @@ class CourseAttributes():
|
|||||||
[Ent.COURSE, self.courseId], Msg.DUPLICATE, j, jcount)
|
[Ent.COURSE, self.courseId], Msg.DUPLICATE, j, jcount)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
result = callGAPI(tcroom.courses().topics(), 'create',
|
result = callGAPI(self.tcroom.courses().topics(), 'create',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION, GAPI.INVALID_ARGUMENT, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION, GAPI.INVALID_ARGUMENT, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
courseId=newCourseId, body={'name': topicName}, fields='topicId')
|
courseId=newCourseId, body={'name': topicName}, fields='topicId')
|
||||||
@@ -44583,7 +44595,7 @@ class CourseAttributes():
|
|||||||
if self.copyMaterialsFiles:
|
if self.copyMaterialsFiles:
|
||||||
self.CopyMaterials(tdrive, newCourseId, body, Ent.COURSE_ANNOUNCEMENT_ID, courseAnnouncementId, teacherFolderId)
|
self.CopyMaterials(tdrive, newCourseId, body, Ent.COURSE_ANNOUNCEMENT_ID, courseAnnouncementId, teacherFolderId)
|
||||||
try:
|
try:
|
||||||
result = callGAPI(tcroom.courses().announcements(), 'create',
|
result = callGAPI(self.tcroom.courses().announcements(), 'create',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
||||||
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR, GAPI.INTERNAL_ERROR, GAPI.SERVICE_NOT_AVAILABLE],
|
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR, GAPI.INTERNAL_ERROR, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44619,7 +44631,7 @@ class CourseAttributes():
|
|||||||
if newTopicId:
|
if newTopicId:
|
||||||
body['topicId'] = newTopicId
|
body['topicId'] = newTopicId
|
||||||
try:
|
try:
|
||||||
result = callGAPI(tcroom.courses().courseWorkMaterials(), 'create',
|
result = callGAPI(self.tcroom.courses().courseWorkMaterials(), 'create',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
||||||
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR, GAPI.INTERNAL_ERROR, GAPI.SERVICE_NOT_AVAILABLE],
|
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR, GAPI.INTERNAL_ERROR, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
@@ -44658,7 +44670,7 @@ class CourseAttributes():
|
|||||||
body.pop('dueDate', None)
|
body.pop('dueDate', None)
|
||||||
body.pop('dueTime', None)
|
body.pop('dueTime', None)
|
||||||
try:
|
try:
|
||||||
result = callGAPI(tcroom.courses().courseWork(), 'create',
|
result = callGAPI(self.tcroom.courses().courseWork(), 'create',
|
||||||
bailOnInternalError=True,
|
bailOnInternalError=True,
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.FORBIDDEN,
|
||||||
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR,
|
GAPI.BAD_REQUEST, GAPI.FAILED_PRECONDITION, GAPI.BACKEND_ERROR,
|
||||||
@@ -45003,6 +45015,30 @@ def _convertCourseUserIdToEmail(croom, userId, emails, entityValueList, i, count
|
|||||||
emails[userId] = userEmail
|
emails[userId] = userEmail
|
||||||
return userEmail
|
return userEmail
|
||||||
|
|
||||||
|
def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess):
|
||||||
|
coursesInfo = {}
|
||||||
|
for courseId in courseIds:
|
||||||
|
courseId = addCourseIdScope(courseId)
|
||||||
|
if courseId not in coursesInfo:
|
||||||
|
try:
|
||||||
|
course = callGAPI(croom.courses(), 'get',
|
||||||
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
|
id=courseId, fields='name,ownerId')
|
||||||
|
if useOwnerAccess:
|
||||||
|
_, ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{course["ownerId"]}')
|
||||||
|
else:
|
||||||
|
ocroom = croom
|
||||||
|
if ocroom is not None:
|
||||||
|
coursesInfo[courseId] = {'name': course['name'], 'croom': ocroom}
|
||||||
|
except GAPI.notFound:
|
||||||
|
entityDoesNotExistWarning(Ent.COURSE, courseId)
|
||||||
|
except (GAPI.permissionDenied, GAPI.serviceNotAvailable) as e:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
||||||
|
except GAPI.forbidden:
|
||||||
|
ClientAPIAccessDeniedExit()
|
||||||
|
return 0, len(coursesInfo), coursesInfo
|
||||||
|
|
||||||
def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, showGettings=False, i=0, count=0):
|
def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, showGettings=False, i=0, count=0):
|
||||||
aliases = []
|
aliases = []
|
||||||
teachers = []
|
teachers = []
|
||||||
@@ -45059,7 +45095,7 @@ def _doInfoCourses(courseIdList):
|
|||||||
courseShowProperties = _initCourseShowProperties()
|
courseShowProperties = _initCourseShowProperties()
|
||||||
courseShowProperties['ownerEmail'] = True
|
courseShowProperties['ownerEmail'] = True
|
||||||
ownerEmails = {}
|
ownerEmails = {}
|
||||||
useOwnerAccess = False
|
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
||||||
FJQC = FormatJSONQuoteChar()
|
FJQC = FormatJSONQuoteChar()
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
myarg = getArgument()
|
myarg = getArgument()
|
||||||
@@ -45069,8 +45105,6 @@ def _doInfoCourses(courseIdList):
|
|||||||
useOwnerAccess = True
|
useOwnerAccess = True
|
||||||
else:
|
else:
|
||||||
FJQC.GetFormatJSON(myarg)
|
FJQC.GetFormatJSON(myarg)
|
||||||
coursesInfo = {}
|
|
||||||
_getCoursesOwnerInfo(croom, courseIdList, coursesInfo, not useOwnerAccess)
|
|
||||||
fields = _setCourseFields(courseShowProperties, False)
|
fields = _setCourseFields(courseShowProperties, False)
|
||||||
if courseShowProperties['members'] != 'none':
|
if courseShowProperties['members'] != 'none':
|
||||||
if courseShowProperties['countsOnly']:
|
if courseShowProperties['countsOnly']:
|
||||||
@@ -45081,14 +45115,9 @@ def _doInfoCourses(courseIdList):
|
|||||||
studentsFields = 'nextPageToken,students(profile)'
|
studentsFields = 'nextPageToken,students(profile)'
|
||||||
else:
|
else:
|
||||||
teachersFields = studentsFields = None
|
teachersFields = studentsFields = None
|
||||||
i = 0
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, useOwnerAccess)
|
||||||
count = len(courseIdList)
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
for courseId in courseIdList:
|
|
||||||
i += 1
|
i += 1
|
||||||
courseId = addCourseIdScope(courseId)
|
|
||||||
courseInfo = coursesInfo[courseId]
|
|
||||||
if not courseInfo:
|
|
||||||
continue
|
|
||||||
try:
|
try:
|
||||||
course = callGAPI(croom.courses(), 'get',
|
course = callGAPI(croom.courses(), 'get',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
@@ -45159,12 +45188,14 @@ def _doInfoCourses(courseIdList):
|
|||||||
except GAPI.forbidden:
|
except GAPI.forbidden:
|
||||||
ClientAPIAccessDeniedExit()
|
ClientAPIAccessDeniedExit()
|
||||||
|
|
||||||
# gam info courses <CourseEntity> [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
|
# gam info courses <CourseEntity> [owneraccess]
|
||||||
|
# [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
|
||||||
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
|
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
|
||||||
def doInfoCourses():
|
def doInfoCourses():
|
||||||
_doInfoCourses(getEntityList(Cmd.OB_COURSE_ENTITY, shlexSplit=True))
|
_doInfoCourses(getEntityList(Cmd.OB_COURSE_ENTITY, shlexSplit=True))
|
||||||
|
|
||||||
# gam info course <CourseID> [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
|
# gam info course <CourseID> [owneraccess]
|
||||||
|
# [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
|
||||||
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
|
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
|
||||||
def doInfoCourse():
|
def doInfoCourse():
|
||||||
_doInfoCourses(getStringReturnInList(Cmd.OB_COURSE_ID))
|
_doInfoCourses(getStringReturnInList(Cmd.OB_COURSE_ID))
|
||||||
@@ -45322,6 +45353,7 @@ def doPrintCourses():
|
|||||||
ownerEmails = {}
|
ownerEmails = {}
|
||||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||||
showItemCountOnly = False
|
showItemCountOnly = False
|
||||||
|
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
myarg = getArgument()
|
myarg = getArgument()
|
||||||
if myarg == 'todrive':
|
if myarg == 'todrive':
|
||||||
@@ -45342,7 +45374,7 @@ def doPrintCourses():
|
|||||||
if applyCourseItemFilter:
|
if applyCourseItemFilter:
|
||||||
if courseShowProperties['fields']:
|
if courseShowProperties['fields']:
|
||||||
courseShowProperties['fields'].append(courseItemFilter['timefilter'])
|
courseShowProperties['fields'].append(courseItemFilter['timefilter'])
|
||||||
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties)
|
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
|
||||||
if coursesInfo is None:
|
if coursesInfo is None:
|
||||||
if showItemCountOnly:
|
if showItemCountOnly:
|
||||||
writeStdout('0\n')
|
writeStdout('0\n')
|
||||||
@@ -45381,6 +45413,12 @@ def doPrintCourses():
|
|||||||
for field in courseShowProperties['skips']:
|
for field in courseShowProperties['skips']:
|
||||||
course.pop(field, None)
|
course.pop(field, None)
|
||||||
courseId = course['id']
|
courseId = course['id']
|
||||||
|
if useOwnerAccess:
|
||||||
|
_, ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{course["ownerId"]}')
|
||||||
|
if not ocroom:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
ocroom = croom
|
||||||
if courseShowProperties['ownerEmail']:
|
if courseShowProperties['ownerEmail']:
|
||||||
course['ownerEmail'] = _convertCourseUserIdToEmail(croom, course['ownerId'], ownerEmails,
|
course['ownerEmail'] = _convertCourseUserIdToEmail(croom, course['ownerId'], ownerEmails,
|
||||||
[Ent.COURSE, courseId, Ent.OWNER_ID, course['ownerId']], i, count)
|
[Ent.COURSE, courseId, Ent.OWNER_ID, course['ownerId']], i, count)
|
||||||
@@ -45389,7 +45427,7 @@ def doPrintCourses():
|
|||||||
if showItemCountOnly:
|
if showItemCountOnly:
|
||||||
itemCount += 1
|
itemCount += 1
|
||||||
continue
|
continue
|
||||||
aliases, teachers, students = _getCourseAliasesMembers(croom, croom, courseId, courseShowProperties, teachersFields, studentsFields, True, i, count)
|
aliases, teachers, students = _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, True, i, count)
|
||||||
if courseShowProperties['aliases']:
|
if courseShowProperties['aliases']:
|
||||||
if not courseShowProperties['aliasesInColumns']:
|
if not courseShowProperties['aliasesInColumns']:
|
||||||
course['Aliases'] = delimiter.join([removeCourseAliasScope(alias['alias']) for alias in aliases])
|
course['Aliases'] = delimiter.join([removeCourseAliasScope(alias['alias']) for alias in aliases])
|
||||||
@@ -45614,7 +45652,6 @@ def doPrintCourseTopics():
|
|||||||
courseId = course['id']
|
courseId = course['id']
|
||||||
if courseTopicIdsLists:
|
if courseTopicIdsLists:
|
||||||
courseTopicIds = courseTopicIdsLists[courseId]
|
courseTopicIds = courseTopicIdsLists[courseId]
|
||||||
|
|
||||||
if not courseTopicIds:
|
if not courseTopicIds:
|
||||||
fields = getItemFieldsFromFieldsList('topic', fieldsList)
|
fields = getItemFieldsFromFieldsList('topic', fieldsList)
|
||||||
printGettingAllEntityItemsForWhom(Ent.COURSE_TOPIC, Ent.TypeName(Ent.COURSE, courseId), i, count)
|
printGettingAllEntityItemsForWhom(Ent.COURSE_TOPIC, Ent.TypeName(Ent.COURSE, courseId), i, count)
|
||||||
@@ -46098,6 +46135,7 @@ def doPrintCourseParticipants():
|
|||||||
courseShowProperties = _initCourseShowProperties(['name'])
|
courseShowProperties = _initCourseShowProperties(['name'])
|
||||||
courseShowProperties['members'] = 'all'
|
courseShowProperties['members'] = 'all'
|
||||||
showItemCountOnly = False
|
showItemCountOnly = False
|
||||||
|
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
myarg = getArgument()
|
myarg = getArgument()
|
||||||
if myarg == 'todrive':
|
if myarg == 'todrive':
|
||||||
@@ -46110,7 +46148,7 @@ def doPrintCourseParticipants():
|
|||||||
showItemCountOnly = True
|
showItemCountOnly = True
|
||||||
else:
|
else:
|
||||||
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
||||||
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties)
|
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
|
||||||
if coursesInfo is None:
|
if coursesInfo is None:
|
||||||
if showItemCountOnly:
|
if showItemCountOnly:
|
||||||
writeStdout('0\n')
|
writeStdout('0\n')
|
||||||
@@ -46132,7 +46170,13 @@ def doPrintCourseParticipants():
|
|||||||
for course in coursesInfo:
|
for course in coursesInfo:
|
||||||
i += 1
|
i += 1
|
||||||
courseId = course['id']
|
courseId = course['id']
|
||||||
_, teachers, students = _getCourseAliasesMembers(croom, croom, courseId, courseShowProperties, teachersFields, studentsFields, True, i, count)
|
if useOwnerAccess:
|
||||||
|
_, ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{course["ownerId"]}')
|
||||||
|
if not ocroom:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
ocroom = croom
|
||||||
|
_, teachers, students = _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, True, i, count)
|
||||||
if showItemCountOnly:
|
if showItemCountOnly:
|
||||||
if courseShowProperties['members'] != 'students':
|
if courseShowProperties['members'] != 'students':
|
||||||
itemCount += len(teachers)
|
itemCount += len(teachers)
|
||||||
@@ -46319,29 +46363,6 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, r
|
|||||||
dbatch.execute()
|
dbatch.execute()
|
||||||
Ind.Decrement()
|
Ind.Decrement()
|
||||||
|
|
||||||
def _getCoursesOwnerInfo(croom, courseIds, coursesInfo, useAdminAccess):
|
|
||||||
for courseId in courseIds:
|
|
||||||
courseId = addCourseIdScope(courseId)
|
|
||||||
if courseId not in coursesInfo:
|
|
||||||
coursesInfo[courseId] = {}
|
|
||||||
try:
|
|
||||||
info = callGAPI(croom.courses(), 'get',
|
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
||||||
id=courseId, fields='name,ownerId')
|
|
||||||
if not useAdminAccess:
|
|
||||||
_, ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{info["ownerId"]}')
|
|
||||||
else:
|
|
||||||
ocroom = croom
|
|
||||||
if ocroom is not None:
|
|
||||||
coursesInfo[courseId] = {'name': info['name'], 'croom': ocroom}
|
|
||||||
except GAPI.notFound:
|
|
||||||
entityDoesNotExistWarning(Ent.COURSE, courseId)
|
|
||||||
except (GAPI.permissionDenied, GAPI.serviceNotAvailable) as e:
|
|
||||||
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
|
||||||
except GAPI.forbidden:
|
|
||||||
ClientAPIAccessDeniedExit()
|
|
||||||
|
|
||||||
def _updateCourseOwner(croom, courseId, owner, i, count):
|
def _updateCourseOwner(croom, courseId, owner, i, count):
|
||||||
action = Act.Get()
|
action = Act.Get()
|
||||||
Act.Set(Act.UPDATE_OWNER)
|
Act.Set(Act.UPDATE_OWNER)
|
||||||
@@ -46398,7 +46419,6 @@ def doCourseAddItems(courseIdList, getEntityListArg):
|
|||||||
makeFirstTeacherOwner = checkArgumentPresent(['makefirstteacherowner'])
|
makeFirstTeacherOwner = checkArgumentPresent(['makefirstteacherowner'])
|
||||||
else:
|
else:
|
||||||
makeFirstTeacherOwner = False
|
makeFirstTeacherOwner = False
|
||||||
coursesInfo = {}
|
|
||||||
if not getEntityListArg:
|
if not getEntityListArg:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if role in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
addItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
addItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
||||||
@@ -46422,22 +46442,17 @@ def doCourseAddItems(courseIdList, getEntityListArg):
|
|||||||
if makeFirstTeacherOwner and addItems:
|
if makeFirstTeacherOwner and addItems:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
_getCoursesOwnerInfo(croom, courseIdList, coursesInfo, role != Ent.COURSE_TOPIC)
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, role == Ent.COURSE_TOPIC)
|
||||||
i = 0
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
count = len(courseIdList)
|
|
||||||
for courseId in courseIdList:
|
|
||||||
i += 1
|
i += 1
|
||||||
if courseParticipantLists:
|
if courseParticipantLists:
|
||||||
addItems = courseParticipantLists[courseId]
|
addItems = courseParticipantLists[courseId]
|
||||||
firstTeacher = None
|
firstTeacher = None
|
||||||
if makeFirstTeacherOwner and addItems:
|
if makeFirstTeacherOwner and addItems:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
||||||
courseId = addCourseIdScope(courseId)
|
_batchAddItemsToCourse(courseInfo['croom'], courseId, i, count, addItems, role)
|
||||||
courseInfo = coursesInfo[courseId]
|
if makeFirstTeacherOwner and firstTeacher:
|
||||||
if courseInfo:
|
_updateCourseOwner(courseInfo['croom'], courseId, firstTeacher, i, count)
|
||||||
_batchAddItemsToCourse(courseInfo['croom'], courseId, i, count, addItems, role)
|
|
||||||
if makeFirstTeacherOwner and firstTeacher:
|
|
||||||
_updateCourseOwner(courseInfo['croom'], courseId, firstTeacher, i, count)
|
|
||||||
|
|
||||||
# gam courses <CourseEntity> remove alias <CourseAliasEntity>
|
# gam courses <CourseEntity> remove alias <CourseAliasEntity>
|
||||||
# gam course <CourseID> remove alias <CourseAlias>
|
# gam course <CourseID> remove alias <CourseAlias>
|
||||||
@@ -46448,10 +46463,11 @@ def doCourseAddItems(courseIdList, getEntityListArg):
|
|||||||
def doCourseRemoveItems(courseIdList, getEntityListArg):
|
def doCourseRemoveItems(courseIdList, getEntityListArg):
|
||||||
croom = buildGAPIObject(API.CLASSROOM)
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
role = getChoice(ADD_REMOVE_PARTICIPANT_TYPES_MAP, mapChoice=True)
|
role = getChoice(ADD_REMOVE_PARTICIPANT_TYPES_MAP, mapChoice=True)
|
||||||
coursesInfo = {}
|
|
||||||
if not getEntityListArg:
|
if not getEntityListArg:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if role in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
useOwnerAccess = checkArgumentPresent(OWNER_ACCESS_OPTIONS)
|
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
||||||
|
if checkArgumentPresent(OWNER_ACCESS_OPTIONS):
|
||||||
|
useOwnerAccess = True
|
||||||
removeItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
removeItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif role == Ent.COURSE_ALIAS:
|
||||||
useOwnerAccess = False
|
useOwnerAccess = False
|
||||||
@@ -46473,17 +46489,12 @@ def doCourseRemoveItems(courseIdList, getEntityListArg):
|
|||||||
removeItems = getEntityList(Cmd.OB_COURSE_TOPIC_ID_ENTITY, shlexSplit=True)
|
removeItems = getEntityList(Cmd.OB_COURSE_TOPIC_ID_ENTITY, shlexSplit=True)
|
||||||
courseParticipantLists = removeItems if isinstance(removeItems, dict) else None
|
courseParticipantLists = removeItems if isinstance(removeItems, dict) else None
|
||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
_getCoursesOwnerInfo(croom, courseIdList, coursesInfo, not useOwnerAccess)
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, useOwnerAccess)
|
||||||
i = 0
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
count = len(courseIdList)
|
|
||||||
for courseId in courseIdList:
|
|
||||||
i += 1
|
i += 1
|
||||||
if courseParticipantLists:
|
if courseParticipantLists:
|
||||||
removeItems = courseParticipantLists[courseId]
|
removeItems = courseParticipantLists[courseId]
|
||||||
courseId = addCourseIdScope(courseId)
|
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, role)
|
||||||
courseInfo = coursesInfo[courseId]
|
|
||||||
if courseInfo:
|
|
||||||
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, role)
|
|
||||||
|
|
||||||
# gam courses <CourseEntity> clear teachers|students
|
# gam courses <CourseEntity> clear teachers|students
|
||||||
# gam course <CourseID> clear teacher|student
|
# gam course <CourseID> clear teacher|student
|
||||||
@@ -46491,14 +46502,13 @@ def doCourseClearParticipants(courseIdList, getEntityListArg):
|
|||||||
croom = buildGAPIObject(API.CLASSROOM)
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True)
|
role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True)
|
||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
i = 0
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
||||||
count = len(courseIdList)
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
for courseId in courseIdList:
|
|
||||||
i += 1
|
i += 1
|
||||||
removeParticipants = getItemsToModify(PARTICIPANT_EN_MAP[role], courseId, noListConversion=True)
|
removeParticipants = getItemsToModify(PARTICIPANT_EN_MAP[role], courseId, noListConversion=True)
|
||||||
if GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE]:
|
if GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE]:
|
||||||
continue
|
continue
|
||||||
_batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, role)
|
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeParticipants, role)
|
||||||
|
|
||||||
# gam courses <CourseEntity> sync students [addonly|removeonly] <UserTypeEntity>
|
# gam courses <CourseEntity> sync students [addonly|removeonly] <UserTypeEntity>
|
||||||
# gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
|
# gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
|
||||||
@@ -46525,9 +46535,8 @@ def doCourseSyncParticipants(courseIdList, getEntityListArg):
|
|||||||
syncParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
syncParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
||||||
if makeFirstTeacherOwner:
|
if makeFirstTeacherOwner:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(syncParticipants[0])
|
firstTeacher = normalizeEmailAddressOrUID(syncParticipants[0])
|
||||||
i = 0
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
||||||
count = len(courseIdList)
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
for courseId in courseIdList:
|
|
||||||
i += 1
|
i += 1
|
||||||
if courseParticipantLists:
|
if courseParticipantLists:
|
||||||
syncParticipantsSet = set()
|
syncParticipantsSet = set()
|
||||||
@@ -46537,21 +46546,18 @@ def doCourseSyncParticipants(courseIdList, getEntityListArg):
|
|||||||
syncParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
syncParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
||||||
if makeFirstTeacherOwner:
|
if makeFirstTeacherOwner:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(courseParticipantLists[courseId][0])
|
firstTeacher = normalizeEmailAddressOrUID(courseParticipantLists[courseId][0])
|
||||||
courseInfo = checkCourseExists(croom, courseId, i, count)
|
currentParticipantsSet = set()
|
||||||
if courseInfo:
|
currentParticipants = getItemsToModify(PARTICIPANT_EN_MAP[role], courseId, noListConversion=True)
|
||||||
courseId = courseInfo['id']
|
if GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE]:
|
||||||
currentParticipantsSet = set()
|
continue
|
||||||
currentParticipants = getItemsToModify(PARTICIPANT_EN_MAP[role], courseId, noListConversion=True)
|
for user in currentParticipants:
|
||||||
if GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE]:
|
currentParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
||||||
continue
|
if syncOperation != 'removeonly':
|
||||||
for user in currentParticipants:
|
_batchAddItemsToCourse(croom, courseId, i, count, list(syncParticipantsSet-currentParticipantsSet), role)
|
||||||
currentParticipantsSet.add(normalizeEmailAddressOrUID(user))
|
if makeFirstTeacherOwner and firstTeacher:
|
||||||
if syncOperation != 'removeonly':
|
_updateCourseOwner(croom, courseId, firstTeacher, i, count)
|
||||||
_batchAddItemsToCourse(croom, courseId, i, count, list(syncParticipantsSet-currentParticipantsSet), role)
|
if syncOperation != 'addonly':
|
||||||
if makeFirstTeacherOwner and firstTeacher:
|
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, list(currentParticipantsSet-syncParticipantsSet), role)
|
||||||
_updateCourseOwner(croom, courseId, firstTeacher, i, count)
|
|
||||||
if syncOperation != 'addonly':
|
|
||||||
_batchRemoveItemsFromCourse(croom, courseId, i, count, list(currentParticipantsSet-syncParticipantsSet), role)
|
|
||||||
|
|
||||||
def studentUnknownWarning(studentId, errMsg, i, count):
|
def studentUnknownWarning(studentId, errMsg, i, count):
|
||||||
setSysExitRC(SERVICE_NOT_APPLICABLE_RC)
|
setSysExitRC(SERVICE_NOT_APPLICABLE_RC)
|
||||||
@@ -47208,9 +47214,8 @@ def createClassroomInvitations(users):
|
|||||||
croom = buildGAPIObject(API.CLASSROOM)
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
classroomEmails = {}
|
classroomEmails = {}
|
||||||
courseIds = None
|
courseIds = None
|
||||||
coursesInfo = {}
|
|
||||||
role = CLASSROOM_ROLE_STUDENT
|
role = CLASSROOM_ROLE_STUDENT
|
||||||
useAdminAccess = False
|
useOwnerAccess = True
|
||||||
csvPF = None
|
csvPF = None
|
||||||
FJQC = FormatJSONQuoteChar(csvPF)
|
FJQC = FormatJSONQuoteChar(csvPF)
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
@@ -47225,20 +47230,20 @@ def createClassroomInvitations(users):
|
|||||||
elif csvPF and myarg == 'todrive':
|
elif csvPF and myarg == 'todrive':
|
||||||
csvPF.GetTodriveParameters()
|
csvPF.GetTodriveParameters()
|
||||||
elif myarg in ADMIN_ACCESS_OPTIONS:
|
elif myarg in ADMIN_ACCESS_OPTIONS:
|
||||||
useAdminAccess = True
|
useOwnerAccess = False
|
||||||
else:
|
else:
|
||||||
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
||||||
if courseIds is None:
|
if courseIds is None:
|
||||||
missingArgumentExit('courses <CourseEntity>')
|
missingArgumentExit('courses <CourseEntity>')
|
||||||
if csvPF:
|
if csvPF:
|
||||||
if FJQC.formatJSON:
|
if FJQC.formatJSON:
|
||||||
csvPF.SetTitles(['userEmail', 'JSON'])
|
csvPF.SetJSONTitles(['userEmail', 'JSON'])
|
||||||
else:
|
else:
|
||||||
csvPF.SetTitles(['userId', 'userEmail', 'courseId', 'courseName', 'id', 'role'])
|
csvPF.SetTitles(['userEmail', 'courseId', 'courseName', 'id', 'role'])
|
||||||
csvPF.SetSortAllTitles()
|
csvPF.SetSortAllTitles()
|
||||||
courseIdsLists = courseIds if isinstance(courseIds, dict) else None
|
courseIdsLists = courseIds if isinstance(courseIds, dict) else None
|
||||||
if courseIdsLists is None:
|
if courseIdsLists is None:
|
||||||
_getCoursesOwnerInfo(croom, courseIds, coursesInfo, useAdminAccess)
|
j, jcount, coursesInfo = _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess)
|
||||||
entityType = CLASSROOM_ROLE_ENTITY_MAP[role]
|
entityType = CLASSROOM_ROLE_ENTITY_MAP[role]
|
||||||
i, count, users = getEntityArgument(users)
|
i, count, users = getEntityArgument(users)
|
||||||
for user in users:
|
for user in users:
|
||||||
@@ -47246,25 +47251,20 @@ def createClassroomInvitations(users):
|
|||||||
userId = normalizeEmailAddressOrUID(user)
|
userId = normalizeEmailAddressOrUID(user)
|
||||||
userEmail = _getClassroomEmail(croom, classroomEmails, userId, userId)
|
userEmail = _getClassroomEmail(croom, classroomEmails, userId, userId)
|
||||||
if courseIdsLists:
|
if courseIdsLists:
|
||||||
courseIds = courseIdsLists[user]
|
j, jcount, coursesInfo = _getCoursesOwnerInfo(croom, courseIdsLists[user], useOwnerAccess)
|
||||||
_getCoursesOwnerInfo(croom, courseIds, coursesInfo, useAdminAccess)
|
|
||||||
jcount = len(courseIds)
|
|
||||||
if csvPF or not FJQC.formatJSON:
|
if csvPF or not FJQC.formatJSON:
|
||||||
entityPerformActionNumItems([Ent.USER, userId], jcount, entityType, i, count)
|
entityPerformActionNumItems([Ent.USER, userId], jcount, entityType, i, count)
|
||||||
if jcount == 0:
|
if jcount == 0:
|
||||||
continue
|
continue
|
||||||
j = 0
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
for courseId in courseIds:
|
|
||||||
j += 1
|
j += 1
|
||||||
courseId = addCourseIdScope(courseId)
|
|
||||||
courseInfo = coursesInfo[courseId]
|
|
||||||
if not courseInfo:
|
|
||||||
continue
|
|
||||||
courseNameId = f'{courseInfo["name"]} ({courseId})'
|
courseNameId = f'{courseInfo["name"]} ({courseId})'
|
||||||
try:
|
try:
|
||||||
invitation = callGAPI(courseInfo['croom'].invitations(), 'create',
|
invitation = callGAPI(courseInfo['croom'].invitations(), 'create',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.ALREADY_EXISTS, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.ALREADY_EXISTS, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
body={'userId': userId, 'courseId': courseId, 'role': role})
|
body={'userId': userId, 'courseId': courseId, 'role': role})
|
||||||
|
invitation['courseName'] = courseInfo['name']
|
||||||
|
invitation['userEmail'] = userEmail
|
||||||
if not csvPF:
|
if not csvPF:
|
||||||
if not FJQC.formatJSON:
|
if not FJQC.formatJSON:
|
||||||
Ind.Increment()
|
Ind.Increment()
|
||||||
@@ -47274,14 +47274,12 @@ def createClassroomInvitations(users):
|
|||||||
printLine(json.dumps(cleanJSON(invitation), ensure_ascii=False, sort_keys=True))
|
printLine(json.dumps(cleanJSON(invitation), ensure_ascii=False, sort_keys=True))
|
||||||
else:
|
else:
|
||||||
if not FJQC.formatJSON:
|
if not FJQC.formatJSON:
|
||||||
invitation['courseName'] = courseInfo['name']
|
|
||||||
invitation['userEmail'] = userEmail
|
|
||||||
csvPF.WriteRow(invitation)
|
csvPF.WriteRow(invitation)
|
||||||
else:
|
else:
|
||||||
csvPF.WriteRowNoFilter({'userEmail': userEmail,
|
csvPF.WriteRowNoFilter({'userEmail': userEmail,
|
||||||
'JSON': json.dumps(cleanJSON(invitation), ensure_ascii=False, sort_keys=True)})
|
'JSON': json.dumps(cleanJSON(invitation), ensure_ascii=False, sort_keys=True)})
|
||||||
except GAPI.permissionDenied:
|
except GAPI.permissionDenied as e:
|
||||||
entityUnknownWarning(Ent.USER, userId, i, count)
|
entityActionFailedWarning([Ent.USER, userId, Ent.COURSE, courseNameId, entityType, None], str(e), j, jcount)
|
||||||
break
|
break
|
||||||
except GAPI.notFound:
|
except GAPI.notFound:
|
||||||
entityUnknownWarning(Ent.COURSE, courseNameId, j, jcount)
|
entityUnknownWarning(Ent.COURSE, courseNameId, j, jcount)
|
||||||
@@ -47422,6 +47420,49 @@ def printShowClassroomInvitations(users):
|
|||||||
if csvPF:
|
if csvPF:
|
||||||
csvPF.writeCSVfile('ClassroomInvitations')
|
csvPF.writeCSVfile('ClassroomInvitations')
|
||||||
|
|
||||||
|
# gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
|
||||||
|
def doDeleteClassroomInvitations():
|
||||||
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
|
courseIdList = invitationIds = None
|
||||||
|
role = CLASSROOM_ROLE_ALL
|
||||||
|
while Cmd.ArgumentsRemaining():
|
||||||
|
myarg = getArgument()
|
||||||
|
if myarg in {'course', 'courses', 'class', 'classes'}:
|
||||||
|
courseIdList = getEntityList(Cmd.OB_COURSE_ENTITY, shlexSplit=True)
|
||||||
|
elif myarg in {'id', 'ids'}:
|
||||||
|
invitationIds = getEntityList(Cmd.OB_CLASSROOM_INVITATION_ID_ENTITY)
|
||||||
|
elif myarg == 'role':
|
||||||
|
role = getChoice(CLASSROOM_ROLE_MAP, mapChoice=True)
|
||||||
|
else:
|
||||||
|
unknownArgumentExit()
|
||||||
|
if courseIdList is None:
|
||||||
|
missingArgumentExit('courses <CourseEntity>')
|
||||||
|
entityType = Ent.CLASSROOM_INVITATION
|
||||||
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, True)
|
||||||
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
|
i += 1
|
||||||
|
courseNameId = f'{courseInfo["name"]} ({courseId})'
|
||||||
|
if invitationIds is not None:
|
||||||
|
userInvitationIds = invitationIds
|
||||||
|
else:
|
||||||
|
status, userInvitationIds = _getClassroomInvitationIds(courseInfo['croom'], None, [courseId], role, i, count)
|
||||||
|
if status < 0:
|
||||||
|
continue
|
||||||
|
jcount = len(userInvitationIds)
|
||||||
|
entityPerformActionNumItems([Ent.COURSE, courseNameId], jcount, entityType, i, count)
|
||||||
|
Ind.Increment()
|
||||||
|
j = 0
|
||||||
|
for invitationId in userInvitationIds:
|
||||||
|
j += 1
|
||||||
|
try:
|
||||||
|
callGAPI(courseInfo['croom'].invitations(), 'delete',
|
||||||
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
|
id=invitationId)
|
||||||
|
entityActionPerformed([Ent.COURSE, courseNameId, entityType, invitationId], j, jcount)
|
||||||
|
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseNameId, entityType, invitationId], str(e), j, jcount)
|
||||||
|
Ind.Decrement()
|
||||||
|
|
||||||
# gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
# gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
# [role all|owner|student|teacher] [formatjson]
|
# [role all|owner|student|teacher] [formatjson]
|
||||||
# gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
# gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||||
@@ -51304,6 +51345,11 @@ def _mapDriveRevisionNames(revision):
|
|||||||
revision['lastModifyingUserName'] = revision['lastModifyingUser']['displayName']
|
revision['lastModifyingUserName'] = revision['lastModifyingUser']['displayName']
|
||||||
_mapDriveUser(revision['lastModifyingUser'])
|
_mapDriveUser(revision['lastModifyingUser'])
|
||||||
|
|
||||||
|
DRIVEFILE_BASIC_PERMISSION_FIELDS = [
|
||||||
|
'displayName', 'id', 'emailAddress', 'domain', 'role', 'type',
|
||||||
|
'allowFileDiscovery', 'expirationTime', 'deleted', 'permissionDetails' #permissionDetails must be last
|
||||||
|
]
|
||||||
|
|
||||||
DRIVE_FIELDS_CHOICE_MAP = {
|
DRIVE_FIELDS_CHOICE_MAP = {
|
||||||
'alternatelink': 'webViewLink',
|
'alternatelink': 'webViewLink',
|
||||||
'appdatacontents': 'spaces',
|
'appdatacontents': 'spaces',
|
||||||
@@ -51362,8 +51408,9 @@ DRIVE_FIELDS_CHOICE_MAP = {
|
|||||||
'ownernames': 'owners.displayName',
|
'ownernames': 'owners.displayName',
|
||||||
'owners': 'owners',
|
'owners': 'owners',
|
||||||
'parents': 'parents',
|
'parents': 'parents',
|
||||||
'permissions': 'permissions',
|
'permissiondetails': 'permissions.permissionDetails',
|
||||||
'permissionids': 'permissionIds',
|
'permissionids': 'permissionIds',
|
||||||
|
'permissions': 'permissions',
|
||||||
'properties': 'properties',
|
'properties': 'properties',
|
||||||
'quotabytesused': 'quotaBytesUsed',
|
'quotabytesused': 'quotaBytesUsed',
|
||||||
'quotaused': 'quotaBytesUsed',
|
'quotaused': 'quotaBytesUsed',
|
||||||
@@ -51719,7 +51766,7 @@ def showFileInfo(users):
|
|||||||
showLabels = getChoice(SHOWLABELS_CHOICES)
|
showLabels = getChoice(SHOWLABELS_CHOICES)
|
||||||
elif myarg == 'showshareddrivepermissions':
|
elif myarg == 'showshareddrivepermissions':
|
||||||
getPermissionsForSharedDrives = True
|
getPermissionsForSharedDrives = True
|
||||||
permissionsFields = 'nextPageToken,permissions'
|
permissionsFields = f'nextPageToken,permissions({",".join(DRIVEFILE_BASIC_PERMISSION_FIELDS)})'
|
||||||
elif myarg == 'returnidonly':
|
elif myarg == 'returnidonly':
|
||||||
returnIdOnly = True
|
returnIdOnly = True
|
||||||
elif DFF.ProcessArgument(myarg):
|
elif DFF.ProcessArgument(myarg):
|
||||||
@@ -51727,7 +51774,8 @@ def showFileInfo(users):
|
|||||||
else:
|
else:
|
||||||
FJQC.GetFormatJSON(myarg)
|
FJQC.GetFormatJSON(myarg)
|
||||||
if DFF.fieldsList:
|
if DFF.fieldsList:
|
||||||
getPermissionsForSharedDrives, permissionsFields = _setGetPermissionsForSharedDrives(DFF.fieldsList)
|
if not getPermissionsForSharedDrives:
|
||||||
|
getPermissionsForSharedDrives, permissionsFields = _setGetPermissionsForSharedDrives(DFF.fieldsList)
|
||||||
_setSelectionFields()
|
_setSelectionFields()
|
||||||
fields = getFieldsFromFieldsList(DFF.fieldsList)
|
fields = getFieldsFromFieldsList(DFF.fieldsList)
|
||||||
showNoParents = 'parents' in DFF.fieldsList
|
showNoParents = 'parents' in DFF.fieldsList
|
||||||
@@ -52581,6 +52629,7 @@ DRIVEFILE_ACL_ROLES_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DRIVEFILE_ACL_PERMISSION_TYPES = ['anyone', 'domain', 'group', 'user'] # anyone must be first element
|
DRIVEFILE_ACL_PERMISSION_TYPES = ['anyone', 'domain', 'group', 'user'] # anyone must be first element
|
||||||
|
DRIVEFILE_ACL_PERMISSION_DETAILS_TYPES = ['file', 'member']
|
||||||
|
|
||||||
class PermissionMatch():
|
class PermissionMatch():
|
||||||
_PERMISSION_MATCH_ACTION_MAP = {'process': True, 'skip': False}
|
_PERMISSION_MATCH_ACTION_MAP = {'process': True, 'skip': False}
|
||||||
@@ -52667,10 +52716,13 @@ class PermissionMatch():
|
|||||||
self.permissionFields.add('expirationTime')
|
self.permissionFields.add('expirationTime')
|
||||||
elif myarg == 'deleted':
|
elif myarg == 'deleted':
|
||||||
deletedLocation = Cmd.Location()
|
deletedLocation = Cmd.Location()
|
||||||
body['deleted'] = getBoolean()
|
body[myarg] = getBoolean()
|
||||||
self.permissionFields.add('deleted')
|
self.permissionFields.add('deleted')
|
||||||
elif myarg == 'inherited':
|
elif myarg == 'inherited':
|
||||||
body['inherited'] = getBoolean()
|
body[myarg] = getBoolean()
|
||||||
|
self.permissionFields.add('permissionDetails')
|
||||||
|
elif myarg == 'permtype':
|
||||||
|
body['permissionType'] = getChoice(DRIVEFILE_ACL_PERMISSION_DETAILS_TYPES)
|
||||||
self.permissionFields.add('permissionDetails')
|
self.permissionFields.add('permissionDetails')
|
||||||
elif myarg in {'em', 'endmatch'}:
|
elif myarg in {'em', 'endmatch'}:
|
||||||
break
|
break
|
||||||
@@ -52710,21 +52762,27 @@ class PermissionMatch():
|
|||||||
if field in {'type', 'role'}:
|
if field in {'type', 'role'}:
|
||||||
if permission.get(field, '') not in value:
|
if permission.get(field, '') not in value:
|
||||||
break
|
break
|
||||||
elif field in {'nottype'}:
|
elif field == 'nottype':
|
||||||
if permission.get('type', '') in value:
|
if permission.get('type', '') in value:
|
||||||
break
|
break
|
||||||
elif field in {'notrole'}:
|
elif field == 'notrole':
|
||||||
if permission.get('role', '') in value:
|
if permission.get('role', '') in value:
|
||||||
break
|
break
|
||||||
elif field in {'allowFileDiscovery', 'deleted'}:
|
elif field in {'allowFileDiscovery', 'deleted'}:
|
||||||
if value != permission.get(field, False):
|
if value != permission.get(field, False):
|
||||||
break
|
break
|
||||||
elif field in {'inherited'}:
|
elif field == 'inherited':
|
||||||
if 'permissionDetails' in permission:
|
if 'permissionDetails' in permission:
|
||||||
if value != permission['permissionDetails'][0].get(field, False):
|
if value != permission['permissionDetails'][0].get(field, False):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
elif field == 'permissionType':
|
||||||
|
if 'permissionDetails' in permission:
|
||||||
|
if value != permission['permissionDetails'][0].get(field, ''):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
elif field in {'expirationstart', 'expirationend'}:
|
elif field in {'expirationstart', 'expirationend'}:
|
||||||
if 'expirationTime' in permission:
|
if 'expirationTime' in permission:
|
||||||
expirationDateTime, _ = iso8601.parse_date(permission['expirationTime'])
|
expirationDateTime, _ = iso8601.parse_date(permission['expirationTime'])
|
||||||
@@ -52736,14 +52794,14 @@ class PermissionMatch():
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
elif field in {'emailaddresslist'}:
|
elif field == 'emailaddresslist':
|
||||||
emailAddress = permission.get('emailAddress')
|
emailAddress = permission.get('emailAddress')
|
||||||
if emailAddress:
|
if emailAddress:
|
||||||
if emailAddress not in value:
|
if emailAddress not in value:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
elif field in {'permissionidlist'}:
|
elif field == 'permissionidlist':
|
||||||
permissionId = permission.get('id')
|
permissionId = permission.get('id')
|
||||||
if permissionId:
|
if permissionId:
|
||||||
if permissionId not in value:
|
if permissionId not in value:
|
||||||
@@ -53141,6 +53199,16 @@ def printFileList(users):
|
|||||||
if DLP.onlySharedDrives or getPermissionsForSharedDrives or DFF.showSharedDriveNames:
|
if DLP.onlySharedDrives or getPermissionsForSharedDrives or DFF.showSharedDriveNames:
|
||||||
_setSkipObjects(skipObjects, ['driveId'], DFF.fieldsList)
|
_setSkipObjects(skipObjects, ['driveId'], DFF.fieldsList)
|
||||||
|
|
||||||
|
def _printFileInfoRow(baserow, fileInfo):
|
||||||
|
row = baserow.copy()
|
||||||
|
if not FJQC.formatJSON:
|
||||||
|
csvPF.WriteRowTitles(flattenJSON(fileInfo, flattened=row, skipObjects=skipObjects, timeObjects=timeObjects,
|
||||||
|
simpleLists=simpleLists, delimiter=delimiter))
|
||||||
|
else:
|
||||||
|
row['JSON'] = json.dumps(cleanJSON(fileInfo, skipObjects=skipObjects, timeObjects=timeObjects),
|
||||||
|
ensure_ascii=False, sort_keys=True)
|
||||||
|
csvPF.WriteRowTitlesJSONNoFilter(row)
|
||||||
|
|
||||||
def _printFileInfo(drive, user, f_file, cleanFileName):
|
def _printFileInfo(drive, user, f_file, cleanFileName):
|
||||||
driveId = f_file.get('driveId')
|
driveId = f_file.get('driveId')
|
||||||
checkSharedDrivePermissions = getPermissionsForSharedDrives and driveId and 'permissions' not in f_file
|
checkSharedDrivePermissions = getPermissionsForSharedDrives and driveId and 'permissions' not in f_file
|
||||||
@@ -53218,18 +53286,15 @@ def printFileList(users):
|
|||||||
baserow[fileNameTitle] = fileInfo[fileNameTitle]
|
baserow[fileNameTitle] = fileInfo[fileNameTitle]
|
||||||
if 'owners' in fileInfo:
|
if 'owners' in fileInfo:
|
||||||
flattenJSON({'owners': fileInfo['owners']}, flattened=baserow, skipObjects=skipObjects)
|
flattenJSON({'owners': fileInfo['owners']}, flattened=baserow, skipObjects=skipObjects)
|
||||||
permissions = fileInfo.pop('permissions')
|
for permission in fileInfo.pop('permissions'):
|
||||||
for permission in permissions:
|
|
||||||
row = baserow.copy()
|
|
||||||
fileInfo['permission'] = permission
|
fileInfo['permission'] = permission
|
||||||
if not FJQC.formatJSON:
|
pdetails = fileInfo['permission'].pop('permissionDetails', [])
|
||||||
csvPF.WriteRowTitles(flattenJSON(fileInfo, flattened=row, skipObjects=skipObjects, timeObjects=timeObjects,
|
if not pdetails:
|
||||||
simpleLists=simpleLists, delimiter=delimiter))
|
_printFileInfoRow(baserow, fileInfo)
|
||||||
else:
|
else:
|
||||||
row = baserow.copy()
|
for pdetail in pdetails:
|
||||||
row['JSON'] = json.dumps(cleanJSON(fileInfo, skipObjects=skipObjects, timeObjects=timeObjects),
|
fileInfo['permission']['permissionDetails'] = pdetail
|
||||||
ensure_ascii=False, sort_keys=True)
|
_printFileInfoRow(baserow, fileInfo)
|
||||||
csvPF.WriteRowTitlesJSONNoFilter(row)
|
|
||||||
else:
|
else:
|
||||||
if not countsRowFilter:
|
if not countsRowFilter:
|
||||||
csvPF.UpdateMimeTypeCounts(flattenJSON(fileInfo, flattened=row, skipObjects=skipObjects, timeObjects=timeObjects,
|
csvPF.UpdateMimeTypeCounts(flattenJSON(fileInfo, flattened=row, skipObjects=skipObjects, timeObjects=timeObjects,
|
||||||
@@ -53417,7 +53482,7 @@ def printFileList(users):
|
|||||||
showLabels = getChoice(SHOWLABELS_CHOICES)
|
showLabels = getChoice(SHOWLABELS_CHOICES)
|
||||||
elif myarg == 'showshareddrivepermissions':
|
elif myarg == 'showshareddrivepermissions':
|
||||||
getPermissionsForSharedDrives = True
|
getPermissionsForSharedDrives = True
|
||||||
permissionsFields = 'nextPageToken,permissions'
|
permissionsFields = f'nextPageToken,permissions({",".join(DRIVEFILE_BASIC_PERMISSION_FIELDS)})'
|
||||||
elif myarg == 'pmfilter':
|
elif myarg == 'pmfilter':
|
||||||
pmselect = False
|
pmselect = False
|
||||||
elif myarg == 'oneitemperrow':
|
elif myarg == 'oneitemperrow':
|
||||||
@@ -53459,9 +53524,10 @@ def printFileList(users):
|
|||||||
DLP.Finalize(fileIdEntity)
|
DLP.Finalize(fileIdEntity)
|
||||||
if DLP.PM.permissionMatches:
|
if DLP.PM.permissionMatches:
|
||||||
getPermissionsForSharedDrives = True
|
getPermissionsForSharedDrives = True
|
||||||
permissionsFields = 'nextPageToken,permissions'
|
permissionsFields = f'nextPageToken,permissions({",".join(DRIVEFILE_BASIC_PERMISSION_FIELDS)})'
|
||||||
elif DFF.fieldsList:
|
elif DFF.fieldsList:
|
||||||
getPermissionsForSharedDrives, permissionsFields = _setGetPermissionsForSharedDrives(DFF.fieldsList)
|
if not getPermissionsForSharedDrives:
|
||||||
|
getPermissionsForSharedDrives, permissionsFields = _setGetPermissionsForSharedDrives(DFF.fieldsList)
|
||||||
if DFF.fieldsList:
|
if DFF.fieldsList:
|
||||||
_setSelectionFields()
|
_setSelectionFields()
|
||||||
fields = getFieldsFromFieldsList(DFF.fieldsList)
|
fields = getFieldsFromFieldsList(DFF.fieldsList)
|
||||||
@@ -60875,24 +60941,19 @@ def infoDriveFileACLs(users, useDomainAdminAccess=False):
|
|||||||
def doInfoDriveFileACLs():
|
def doInfoDriveFileACLs():
|
||||||
infoDriveFileACLs([_getAdminEmail()], True)
|
infoDriveFileACLs([_getAdminEmail()], True)
|
||||||
|
|
||||||
DRIVEFILE_BASIC_PERMISSION_FIELDS = [
|
|
||||||
'displayName', 'id', 'emailAddress', 'domain', 'role', 'type',
|
|
||||||
'allowFileDiscovery', 'expirationTime', 'deleted'
|
|
||||||
]
|
|
||||||
|
|
||||||
DRIVEFILE_PERMISSIONS_FOR_VIEW_CHOICES = ['published']
|
DRIVEFILE_PERMISSIONS_FOR_VIEW_CHOICES = ['published']
|
||||||
|
|
||||||
def getDriveFilePermissionsFields(myarg, fieldsList):
|
def getDriveFilePermissionsFields(myarg, fieldsList):
|
||||||
if myarg in DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP:
|
if myarg in DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP:
|
||||||
fieldsList.append(DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP[myarg])
|
fieldsList.append(DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP[myarg])
|
||||||
elif myarg == 'basicpermissions':
|
elif myarg == 'basicpermissions':
|
||||||
fieldsList.extend(DRIVEFILE_BASIC_PERMISSION_FIELDS)
|
fieldsList.extend(DRIVEFILE_BASIC_PERMISSION_FIELDS[:-1])
|
||||||
elif myarg == 'fields':
|
elif myarg == 'fields':
|
||||||
for field in _getFieldsList():
|
for field in _getFieldsList():
|
||||||
if field in DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP:
|
if field in DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP:
|
||||||
fieldsList.append(DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP[field])
|
fieldsList.append(DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP[field])
|
||||||
elif field == 'basicpermissions':
|
elif field == 'basicpermissions':
|
||||||
fieldsList.extend(DRIVEFILE_BASIC_PERMISSION_FIELDS)
|
fieldsList.extend(DRIVEFILE_BASIC_PERMISSION_FIELDS[:-1])
|
||||||
else:
|
else:
|
||||||
invalidChoiceExit(field, DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP, True)
|
invalidChoiceExit(field, DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP, True)
|
||||||
else:
|
else:
|
||||||
@@ -60916,6 +60977,17 @@ def getDriveFilePermissionsFields(myarg, fieldsList):
|
|||||||
# (orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
# (orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||||
# [formatjson] [adminaccess|asadmin]
|
# [formatjson] [adminaccess|asadmin]
|
||||||
def printShowDriveFileACLs(users, useDomainAdminAccess=False):
|
def printShowDriveFileACLs(users, useDomainAdminAccess=False):
|
||||||
|
def _printPermissionRow(baserow, permission):
|
||||||
|
row = baserow.copy()
|
||||||
|
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
|
||||||
|
if not FJQC.formatJSON:
|
||||||
|
csvPF.WriteRowTitles(row)
|
||||||
|
elif csvPF.CheckRowTitles(row):
|
||||||
|
row = baserow.copy()
|
||||||
|
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
|
||||||
|
ensure_ascii=False, sort_keys=True)
|
||||||
|
csvPF.WriteRowNoFilter(row)
|
||||||
|
|
||||||
csvPF = CSVPrintFile(['Owner', 'id'], 'sortall') if Act.csvFormat() else None
|
csvPF = CSVPrintFile(['Owner', 'id'], 'sortall') if Act.csvFormat() else None
|
||||||
FJQC = FormatJSONQuoteChar(csvPF)
|
FJQC = FormatJSONQuoteChar(csvPF)
|
||||||
fileIdEntity = getDriveFileEntity()
|
fileIdEntity = getDriveFileEntity()
|
||||||
@@ -61036,16 +61108,14 @@ def printShowDriveFileACLs(users, useDomainAdminAccess=False):
|
|||||||
baserow[fileNameTitle] = fileName
|
baserow[fileNameTitle] = fileName
|
||||||
if oneItemPerRow:
|
if oneItemPerRow:
|
||||||
for permission in permissions:
|
for permission in permissions:
|
||||||
row = baserow.copy()
|
|
||||||
_mapDrivePermissionNames(permission)
|
_mapDrivePermissionNames(permission)
|
||||||
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
|
pdetails = permission.pop('permissionDetails', [])
|
||||||
if not FJQC.formatJSON:
|
if not pdetails:
|
||||||
csvPF.WriteRowTitles(row)
|
_printPermissionRow(baserow, permission)
|
||||||
elif csvPF.CheckRowTitles(row):
|
else:
|
||||||
row = baserow.copy()
|
for pdetail in pdetails:
|
||||||
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
|
permission['permissionDetails'] = pdetail
|
||||||
ensure_ascii=False, sort_keys=True)
|
_printPermissionRow(baserow, permission)
|
||||||
csvPF.WriteRowNoFilter(row)
|
|
||||||
else:
|
else:
|
||||||
row = baserow.copy()
|
row = baserow.copy()
|
||||||
for permission in permissions:
|
for permission in permissions:
|
||||||
@@ -62287,6 +62357,17 @@ SHOW_NO_PERMISSIONS_DRIVES_CHOICE_MAP = {
|
|||||||
# [shownopermissionsdrives false|true|only]
|
# [shownopermissionsdrives false|true|only]
|
||||||
# [formatjsn]
|
# [formatjsn]
|
||||||
def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
||||||
|
def _printPermissionRow(baserow, permission):
|
||||||
|
row = baserow.copy()
|
||||||
|
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
|
||||||
|
if not FJQC.formatJSON:
|
||||||
|
csvPF.WriteRowTitles(row)
|
||||||
|
elif csvPF.CheckRowTitles(row):
|
||||||
|
row = baserow.copy()
|
||||||
|
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
|
||||||
|
ensure_ascii=False, sort_keys=True)
|
||||||
|
csvPF.WriteRowNoFilter(row)
|
||||||
|
|
||||||
csvPF = CSVPrintFile(['User', 'id', 'name', 'createdTime'], 'sortall') if Act.csvFormat() else None
|
csvPF = CSVPrintFile(['User', 'id', 'name', 'createdTime'], 'sortall') if Act.csvFormat() else None
|
||||||
FJQC = FormatJSONQuoteChar(csvPF)
|
FJQC = FormatJSONQuoteChar(csvPF)
|
||||||
roles = set()
|
roles = set()
|
||||||
@@ -62469,16 +62550,14 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
|||||||
baserow = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name'], 'createdTime': shareddrive['createdTime']}
|
baserow = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name'], 'createdTime': shareddrive['createdTime']}
|
||||||
if shareddrive['permissions']:
|
if shareddrive['permissions']:
|
||||||
for permission in shareddrive['permissions']:
|
for permission in shareddrive['permissions']:
|
||||||
row = baserow.copy()
|
|
||||||
_mapDrivePermissionNames(permission)
|
_mapDrivePermissionNames(permission)
|
||||||
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
|
pdetails = permission.pop('permissionDetails', [])
|
||||||
if not FJQC.formatJSON:
|
if not pdetails:
|
||||||
csvPF.WriteRowTitles(row)
|
_printPermissionRow(baserow, permission)
|
||||||
elif csvPF.CheckRowTitles(row):
|
else:
|
||||||
row = baserow.copy()
|
for pdetail in pdetails:
|
||||||
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
|
permission['permissionDetails'] = pdetail
|
||||||
ensure_ascii=False, sort_keys=True)
|
_printPermissionRow(baserow, permission)
|
||||||
csvPF.WriteRowNoFilter(row)
|
|
||||||
else:
|
else:
|
||||||
if not FJQC.formatJSON:
|
if not FJQC.formatJSON:
|
||||||
csvPF.WriteRowTitles(baserow)
|
csvPF.WriteRowTitles(baserow)
|
||||||
@@ -71448,6 +71527,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|||||||
Cmd.ARG_CHROMENETWORK: doDeleteChromeNetwork,
|
Cmd.ARG_CHROMENETWORK: doDeleteChromeNetwork,
|
||||||
Cmd.ARG_CHROMEPOLICY: doDeleteChromePolicy,
|
Cmd.ARG_CHROMEPOLICY: doDeleteChromePolicy,
|
||||||
Cmd.ARG_CIGROUP: doDeleteCIGroups,
|
Cmd.ARG_CIGROUP: doDeleteCIGroups,
|
||||||
|
Cmd.ARG_CLASSROOMINVITATION: doDeleteClassroomInvitations,
|
||||||
Cmd.ARG_CONTACT: doDeleteDomainContacts,
|
Cmd.ARG_CONTACT: doDeleteDomainContacts,
|
||||||
Cmd.ARG_CONTACTPHOTO: doDeleteDomainContactPhoto,
|
Cmd.ARG_CONTACTPHOTO: doDeleteDomainContactPhoto,
|
||||||
Cmd.ARG_COURSE: doDeleteCourse,
|
Cmd.ARG_COURSE: doDeleteCourse,
|
||||||
|
|||||||
Reference in New Issue
Block a user