gam7 7.19.3__py3-none-any.whl → 7.20.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gam7 might be problematic. Click here for more details.
- gam/__init__.py +491 -20
- gam/gamlib/glcfg.py +4 -0
- gam/gamlib/glclargs.py +5 -0
- gam/gamlib/glentity.py +4 -0
- gam/gamlib/glglobals.py +3 -0
- gam/gamlib/glmsgs.py +1 -1
- gam/googleapiclient/version.py +1 -1
- {gam7-7.19.3.dist-info → gam7-7.20.0.dist-info}/METADATA +1 -1
- {gam7-7.19.3.dist-info → gam7-7.20.0.dist-info}/RECORD +12 -12
- {gam7-7.19.3.dist-info → gam7-7.20.0.dist-info}/WHEEL +0 -0
- {gam7-7.19.3.dist-info → gam7-7.20.0.dist-info}/entry_points.txt +0 -0
- {gam7-7.19.3.dist-info → gam7-7.20.0.dist-info}/licenses/LICENSE +0 -0
gam/__init__.py
CHANGED
|
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
27
|
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
|
28
|
-
__version__ = '7.
|
|
28
|
+
__version__ = '7.20.00'
|
|
29
29
|
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
|
30
30
|
|
|
31
31
|
#pylint: disable=wrong-import-position
|
|
@@ -4731,6 +4731,7 @@ def clearServiceCache(service):
|
|
|
4731
4731
|
return False
|
|
4732
4732
|
|
|
4733
4733
|
DISCOVERY_URIS = [googleapiclient.discovery.V1_DISCOVERY_URI, googleapiclient.discovery.V2_DISCOVERY_URI]
|
|
4734
|
+
CLASSROOM_DEVELOPER_PREVIEW_DISCOVERY_URI = "https://{api}.googleapis.com/$discovery/rest?labels=DEVELOPER_PREVIEW&version={apiVersion}"
|
|
4734
4735
|
|
|
4735
4736
|
# Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM
|
|
4736
4737
|
def getAPIService(api, httpObj):
|
|
@@ -4750,8 +4751,13 @@ def getService(api, httpObj):
|
|
|
4750
4751
|
triesLimit = 3
|
|
4751
4752
|
for n in range(1, triesLimit+1):
|
|
4752
4753
|
try:
|
|
4754
|
+
if api != API.CLASSROOM or not GC.Values[GC.DEVELOPER_PREVIEW_API_KEY]:
|
|
4755
|
+
discoveryServiceUrl = DISCOVERY_URIS[v2discovery]
|
|
4756
|
+
else:
|
|
4757
|
+
discoveryServiceUrl = CLASSROOM_DEVELOPER_PREVIEW_DISCOVERY_URI
|
|
4758
|
+
developerKey = GC.Values[GC.DEVELOPER_PREVIEW_API_KEY]
|
|
4753
4759
|
service = googleapiclient.discovery.build(api, version, http=httpObj, cache_discovery=False,
|
|
4754
|
-
discoveryServiceUrl=
|
|
4760
|
+
discoveryServiceUrl=discoveryServiceUrl, developerKey=developerKey, static_discovery=False)
|
|
4755
4761
|
GM.Globals[GM.CURRENT_API_SERVICES].setdefault(api, {})
|
|
4756
4762
|
GM.Globals[GM.CURRENT_API_SERVICES][api][version] = service._rootDesc.copy()
|
|
4757
4763
|
if GM.Globals[GM.CACHE_DISCOVERY_ONLY]:
|
|
@@ -48430,6 +48436,14 @@ def _convertCourseUserIdToEmail(croom, userId, emails, entityValueList, i, count
|
|
|
48430
48436
|
emails[userId] = userEmail
|
|
48431
48437
|
return userEmail
|
|
48432
48438
|
|
|
48439
|
+
def _getCourseOwnerSA(croom, course, useOwnerAccess):
|
|
48440
|
+
if not useOwnerAccess:
|
|
48441
|
+
return croom
|
|
48442
|
+
courseOwnerId = course["ownerId"]
|
|
48443
|
+
if courseOwnerId not in GM.Globals[GM.CLASSROOM_OWNER_SA]:
|
|
48444
|
+
_, GM.Globals[GM.CLASSROOM_OWNER_SA][courseOwnerId] = buildGAPIServiceObject(API.CLASSROOM, f'uid:{courseOwnerId}')
|
|
48445
|
+
return GM.Globals[GM.CLASSROOM_OWNER_SA][courseOwnerId]
|
|
48446
|
+
|
|
48433
48447
|
def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
|
|
48434
48448
|
coursesInfo = {}
|
|
48435
48449
|
for courseId in courseIds:
|
|
@@ -48443,13 +48457,10 @@ def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
|
|
|
48443
48457
|
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
|
48444
48458
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
48445
48459
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
48446
|
-
id=courseId, fields='name,ownerId')
|
|
48447
|
-
|
|
48448
|
-
_, ocroom = buildGAPIServiceObject(API.CLASSROOM, f'uid:{course["ownerId"]}')
|
|
48449
|
-
else:
|
|
48450
|
-
ocroom = croom
|
|
48460
|
+
id=courseId, fields='id,name,ownerId')
|
|
48461
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
48451
48462
|
if ocroom is not None:
|
|
48452
|
-
coursesInfo[ciCourseId] = {'name': course['name'], 'croom': ocroom}
|
|
48463
|
+
coursesInfo[ciCourseId] = {'id': course['id'], 'name': course['name'], 'croom': ocroom}
|
|
48453
48464
|
except GAPI.notFound:
|
|
48454
48465
|
entityDoesNotExistWarning(Ent.COURSE, courseId)
|
|
48455
48466
|
except GAPI.serviceNotAvailable as e:
|
|
@@ -48836,12 +48847,9 @@ def doPrintCourses():
|
|
|
48836
48847
|
for field in courseShowProperties['skips']:
|
|
48837
48848
|
course.pop(field, None)
|
|
48838
48849
|
courseId = course['id']
|
|
48839
|
-
|
|
48840
|
-
|
|
48841
|
-
|
|
48842
|
-
continue
|
|
48843
|
-
else:
|
|
48844
|
-
ocroom = croom
|
|
48850
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
48851
|
+
if not ocroom:
|
|
48852
|
+
continue
|
|
48845
48853
|
if courseShowProperties['ownerEmail']:
|
|
48846
48854
|
course['ownerEmail'] = _convertCourseUserIdToEmail(croom, course['ownerId'], ownerEmails,
|
|
48847
48855
|
[Ent.COURSE, courseId, Ent.OWNER_ID, course['ownerId']], i, count)
|
|
@@ -49651,12 +49659,9 @@ def doPrintCourseParticipants():
|
|
|
49651
49659
|
for course in coursesInfo:
|
|
49652
49660
|
i += 1
|
|
49653
49661
|
courseId = course['id']
|
|
49654
|
-
|
|
49655
|
-
|
|
49656
|
-
|
|
49657
|
-
continue
|
|
49658
|
-
else:
|
|
49659
|
-
ocroom = croom
|
|
49662
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
49663
|
+
if not ocroom:
|
|
49664
|
+
continue
|
|
49660
49665
|
_, teachers, students = _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, True, i, count)
|
|
49661
49666
|
if showItemCountOnly:
|
|
49662
49667
|
if courseShowProperties['members'] != 'students':
|
|
@@ -51209,6 +51214,461 @@ def printShowClassroomProfile(users):
|
|
|
51209
51214
|
if csvPF:
|
|
51210
51215
|
csvPF.writeCSVfile('Classroom User Profiles')
|
|
51211
51216
|
|
|
51217
|
+
# gam create course-studentgroups
|
|
51218
|
+
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
51219
|
+
# title <String>
|
|
51220
|
+
# [csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
|
|
51221
|
+
def doCreateCourseStudentGroups():
|
|
51222
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51223
|
+
csvPF = None
|
|
51224
|
+
FJQC = FormatJSONQuoteChar(None)
|
|
51225
|
+
courseSelectionParameters = _initCourseSelectionParameters()
|
|
51226
|
+
courseShowProperties = _initCourseShowProperties(['name'])
|
|
51227
|
+
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
|
51228
|
+
kwargs = {'courseId': None, 'body': {}}
|
|
51229
|
+
while Cmd.ArgumentsRemaining():
|
|
51230
|
+
myarg = getArgument()
|
|
51231
|
+
if myarg == 'title':
|
|
51232
|
+
kwargs['body']['title'] = getString(Cmd.OB_STRING)
|
|
51233
|
+
elif _getCourseSelectionParameters(myarg, courseSelectionParameters):
|
|
51234
|
+
pass
|
|
51235
|
+
elif myarg == 'csv':
|
|
51236
|
+
csvPF = CSVPrintFile(['courseId', 'courseName', 'studentGroupId', 'studentGroupTitle'])
|
|
51237
|
+
FJQC = FormatJSONQuoteChar(csvPF)
|
|
51238
|
+
elif csvPF and myarg == 'todrive':
|
|
51239
|
+
csvPF.GetTodriveParameters()
|
|
51240
|
+
else:
|
|
51241
|
+
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
|
51242
|
+
if 'title' not in kwargs['body']:
|
|
51243
|
+
missingArgumentExit('title')
|
|
51244
|
+
if csvPF and FJQC.formatJSON:
|
|
51245
|
+
csvPF.SetJSONTitles(['courseId', 'courseName', 'JSON'])
|
|
51246
|
+
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
|
|
51247
|
+
if coursesInfo is None:
|
|
51248
|
+
return
|
|
51249
|
+
count = len(coursesInfo)
|
|
51250
|
+
i = 0
|
|
51251
|
+
for course in coursesInfo:
|
|
51252
|
+
i += 1
|
|
51253
|
+
courseId = course['id']
|
|
51254
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
51255
|
+
if not ocroom:
|
|
51256
|
+
continue
|
|
51257
|
+
kwargs['courseId'] = courseId
|
|
51258
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, None]
|
|
51259
|
+
try:
|
|
51260
|
+
studentGroup = callGAPI(ocroom.courses().studentGroups(), 'create',
|
|
51261
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51262
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51263
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51264
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51265
|
+
**kwargs)
|
|
51266
|
+
kvList[-1] = f"{studentGroup['title']}({studentGroup['id']})"
|
|
51267
|
+
if not csvPF:
|
|
51268
|
+
entityActionPerformed(kvList, i, count)
|
|
51269
|
+
elif not FJQC.formatJSON:
|
|
51270
|
+
csvPF.WriteRow({'courseId': courseId, 'courseName': course['name'],
|
|
51271
|
+
'studentGroupId': studentGroup['id'], 'studentGroupTitle': studentGroup['title']})
|
|
51272
|
+
else:
|
|
51273
|
+
csvPF.WriteRowNoFilter({'courseId': courseId, 'courseName': course['name'],
|
|
51274
|
+
'JSON': json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=True)})
|
|
51275
|
+
except GAPI.notFound as e:
|
|
51276
|
+
entityActionFailedWarning(kvList, str(e), i, count)
|
|
51277
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51278
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e), i, count)
|
|
51279
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51280
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51281
|
+
if csvPF:
|
|
51282
|
+
csvPF.writeCSVfile('Course Student Groups')
|
|
51283
|
+
|
|
51284
|
+
# gam update course-studentgroup <CourseID> <StudentGroupID> title <String>
|
|
51285
|
+
def doUpdateCourseStudentGroups():
|
|
51286
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51287
|
+
courseId = getString(Cmd.OB_COURSE_ID)
|
|
51288
|
+
studentGroupId = getString(Cmd.OB_STUDENTGROUP_ID)
|
|
51289
|
+
kwargs = {'courseId': courseId, 'id': studentGroupId, 'body': {}, 'updateMask': ''}
|
|
51290
|
+
while Cmd.ArgumentsRemaining():
|
|
51291
|
+
myarg = getArgument()
|
|
51292
|
+
if myarg == 'title':
|
|
51293
|
+
kwargs['body']['title'] = getString(Cmd.OB_STRING)
|
|
51294
|
+
kwargs['updateMask'] = myarg
|
|
51295
|
+
else:
|
|
51296
|
+
unknownArgumentExit()
|
|
51297
|
+
if 'title' not in kwargs['body']:
|
|
51298
|
+
missingArgumentExit('title')
|
|
51299
|
+
_, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
|
51300
|
+
if count == 0:
|
|
51301
|
+
return
|
|
51302
|
+
ocroom = coursesInfo[courseId]['croom']
|
|
51303
|
+
courseId = coursesInfo[courseId]['id']
|
|
51304
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId]
|
|
51305
|
+
try:
|
|
51306
|
+
studentGroup = callGAPI(ocroom.courses().studentGroups(), 'patch',
|
|
51307
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51308
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51309
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51310
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51311
|
+
**kwargs)
|
|
51312
|
+
kvList[-1] = f"{studentGroup['title']}({studentGroup['id']})"
|
|
51313
|
+
entityActionPerformed(kvList)
|
|
51314
|
+
except GAPI.notFound as e:
|
|
51315
|
+
entityActionFailedWarning(kvList, str(e))
|
|
51316
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51317
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51318
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51319
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51320
|
+
|
|
51321
|
+
# gam delete course-studentgroups <CourseID> <StudentGroupIDEntity>
|
|
51322
|
+
def doDeleteCourseStudentGroups():
|
|
51323
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51324
|
+
courseId = getString(Cmd.OB_COURSE_ID)
|
|
51325
|
+
studentGroupIds = getEntityList(Cmd.OB_STUDENTGROUP_ID_ENTITY, shlexSplit=False)
|
|
51326
|
+
checkForExtraneousArguments()
|
|
51327
|
+
_, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
|
51328
|
+
if count == 0:
|
|
51329
|
+
return
|
|
51330
|
+
ocroom = coursesInfo[courseId]['croom']
|
|
51331
|
+
courseId = coursesInfo[courseId]['id']
|
|
51332
|
+
kwargs = {'courseId': courseId, 'id': None}
|
|
51333
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, None]
|
|
51334
|
+
count = len(studentGroupIds)
|
|
51335
|
+
i = 0
|
|
51336
|
+
for studentGroupId in studentGroupIds:
|
|
51337
|
+
i += 1
|
|
51338
|
+
kwargs['id'] = kvList[-1] = studentGroupId
|
|
51339
|
+
try:
|
|
51340
|
+
callGAPI(ocroom.courses().studentGroups(), 'delete',
|
|
51341
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51342
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51343
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51344
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51345
|
+
**kwargs)
|
|
51346
|
+
entityActionPerformed(kvList, i, count)
|
|
51347
|
+
except GAPI.notFound as e:
|
|
51348
|
+
entityActionFailedWarning(kvList, str(e), i, count)
|
|
51349
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51350
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e), i, count)
|
|
51351
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51352
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51353
|
+
|
|
51354
|
+
# gam clear course-studentgroups
|
|
51355
|
+
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
51356
|
+
def doClearCourseStudentGroups():
|
|
51357
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51358
|
+
courseSelectionParameters = _initCourseSelectionParameters()
|
|
51359
|
+
courseShowProperties = _initCourseShowProperties(['name'])
|
|
51360
|
+
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
|
51361
|
+
while Cmd.ArgumentsRemaining():
|
|
51362
|
+
myarg = getArgument()
|
|
51363
|
+
if _getCourseSelectionParameters(myarg, courseSelectionParameters):
|
|
51364
|
+
pass
|
|
51365
|
+
else:
|
|
51366
|
+
unknownArgumentExit()
|
|
51367
|
+
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
|
|
51368
|
+
if coursesInfo is None:
|
|
51369
|
+
return
|
|
51370
|
+
count = len(coursesInfo)
|
|
51371
|
+
i = 0
|
|
51372
|
+
for course in coursesInfo:
|
|
51373
|
+
i += 1
|
|
51374
|
+
courseId = course['id']
|
|
51375
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
51376
|
+
if not ocroom:
|
|
51377
|
+
continue
|
|
51378
|
+
kwargs = {'courseId': courseId, 'id': None}
|
|
51379
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, None]
|
|
51380
|
+
studentGroups = []
|
|
51381
|
+
printGettingEntityItemForWhom(Ent.COURSE_STUDENTGROUP, formatKeyValueList('', [Ent.Singular(Ent.COURSE), courseId], currentCount(i, count)))
|
|
51382
|
+
pageMessage = getPageMessage()
|
|
51383
|
+
try:
|
|
51384
|
+
studentGroups = callGAPIpages(ocroom.courses().studentGroups(), 'list', 'studentGroups',
|
|
51385
|
+
pageMessage=pageMessage,
|
|
51386
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51387
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51388
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51389
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51390
|
+
courseId=courseId)
|
|
51391
|
+
except GAPI.notFound as e:
|
|
51392
|
+
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
|
51393
|
+
continue
|
|
51394
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51395
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51396
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51397
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51398
|
+
jcount = len(studentGroups)
|
|
51399
|
+
entityPerformActionNumItems([Ent.COURSE, courseId], jcount, Ent.COURSE_STUDENTGROUP, i, count)
|
|
51400
|
+
Ind.Increment()
|
|
51401
|
+
j = 0
|
|
51402
|
+
for studentGroup in studentGroups:
|
|
51403
|
+
j += 1
|
|
51404
|
+
kwargs['id'] = kvList[-1] = studentGroup['id']
|
|
51405
|
+
try:
|
|
51406
|
+
callGAPI(ocroom.courses().studentGroups(), 'delete',
|
|
51407
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51408
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51409
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51410
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51411
|
+
**kwargs)
|
|
51412
|
+
entityActionPerformed(kvList, j, jcount)
|
|
51413
|
+
except GAPI.notFound as e:
|
|
51414
|
+
entityActionFailedWarning(kvList, str(e), j, jcount)
|
|
51415
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51416
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e), j, jcount)
|
|
51417
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51418
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51419
|
+
Ind.Decrement()
|
|
51420
|
+
|
|
51421
|
+
# gam print course-studentgroups [todrive <ToDriveAttribute>*]
|
|
51422
|
+
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
51423
|
+
# [showitemcountonly] [formatjson [quotechar <Character>]]
|
|
51424
|
+
def doPrintCourseStudentGroups(showMembers=False):
|
|
51425
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51426
|
+
cd = buildGAPIObject(API.DIRECTORY)
|
|
51427
|
+
csvPF = CSVPrintFile(['courseId', 'courseName', 'studentGroupId', 'studentGroupTitle'])
|
|
51428
|
+
FJQC = FormatJSONQuoteChar(csvPF)
|
|
51429
|
+
courseSelectionParameters = _initCourseSelectionParameters()
|
|
51430
|
+
courseShowProperties = _initCourseShowProperties(['name'])
|
|
51431
|
+
showItemCountOnly = False
|
|
51432
|
+
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
|
51433
|
+
while Cmd.ArgumentsRemaining():
|
|
51434
|
+
myarg = getArgument()
|
|
51435
|
+
if myarg == 'todrive':
|
|
51436
|
+
csvPF.GetTodriveParameters()
|
|
51437
|
+
elif _getCourseSelectionParameters(myarg, courseSelectionParameters):
|
|
51438
|
+
pass
|
|
51439
|
+
elif myarg == 'showitemcountonly':
|
|
51440
|
+
showItemCountOnly = True
|
|
51441
|
+
else:
|
|
51442
|
+
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
|
51443
|
+
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, useOwnerAccess)
|
|
51444
|
+
if coursesInfo is None:
|
|
51445
|
+
if showItemCountOnly:
|
|
51446
|
+
writeStdout('0\n')
|
|
51447
|
+
return
|
|
51448
|
+
itemCount = 0
|
|
51449
|
+
count = len(coursesInfo)
|
|
51450
|
+
i = 0
|
|
51451
|
+
for course in coursesInfo:
|
|
51452
|
+
i += 1
|
|
51453
|
+
courseId = course['id']
|
|
51454
|
+
ocroom = _getCourseOwnerSA(croom, course, useOwnerAccess)
|
|
51455
|
+
if not ocroom:
|
|
51456
|
+
continue
|
|
51457
|
+
studentGroups = []
|
|
51458
|
+
printGettingEntityItemForWhom(Ent.COURSE_STUDENTGROUP, formatKeyValueList('', [Ent.Singular(Ent.COURSE), courseId], currentCount(i, count)))
|
|
51459
|
+
pageMessage = getPageMessage()
|
|
51460
|
+
try:
|
|
51461
|
+
studentGroups = callGAPIpages(ocroom.courses().studentGroups(), 'list', 'studentGroups',
|
|
51462
|
+
pageMessage=pageMessage,
|
|
51463
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51464
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51465
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51466
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51467
|
+
courseId=courseId)
|
|
51468
|
+
except GAPI.notFound as e:
|
|
51469
|
+
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
|
51470
|
+
continue
|
|
51471
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51472
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51473
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51474
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51475
|
+
if not showMembers and showItemCountOnly:
|
|
51476
|
+
itemCount += len(studentGroups)
|
|
51477
|
+
continue
|
|
51478
|
+
for studentGroup in studentGroups:
|
|
51479
|
+
studentGroupId = studentGroup['id']
|
|
51480
|
+
if not showMembers:
|
|
51481
|
+
if not FJQC.formatJSON:
|
|
51482
|
+
csvPF.WriteRowTitles({'courseId': courseId, 'courseName': course['name'],
|
|
51483
|
+
'studentGroupId': studentGroupId, 'studentGroupTitle': studentGroup['title']})
|
|
51484
|
+
else:
|
|
51485
|
+
row = {'courseId': courseId, 'courseName': course['name']}
|
|
51486
|
+
if csvPF.CheckRowTitles(row):
|
|
51487
|
+
row['JSON'] = json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=False)
|
|
51488
|
+
csvPF.WriteRowTitles(row)
|
|
51489
|
+
continue
|
|
51490
|
+
printGettingEntityItemForWhom(Ent.USER, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
|
|
51491
|
+
currentCount(i, count)))
|
|
51492
|
+
pageMessage = getPageMessage()
|
|
51493
|
+
try:
|
|
51494
|
+
students = callGAPIpages(ocroom.courses().studentGroups().studentGroupMembers(), 'list', 'studentGroupMembers',
|
|
51495
|
+
pageMessage=pageMessage,
|
|
51496
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
|
51497
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51498
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51499
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51500
|
+
courseId=courseId, studentGroupId=studentGroupId)
|
|
51501
|
+
if showItemCountOnly:
|
|
51502
|
+
itemCount += len(students)
|
|
51503
|
+
continue
|
|
51504
|
+
for member in students:
|
|
51505
|
+
member['userEmail'] = convertUIDtoEmailAddress(f"id:{member['userId']}", cd=cd, emailTypes=['user'])
|
|
51506
|
+
except GAPI.notFound as e:
|
|
51507
|
+
entityActionFailedWarning([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
|
|
51508
|
+
continue
|
|
51509
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51510
|
+
entityActionFailedExit([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
|
|
51511
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51512
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51513
|
+
if not FJQC.formatJSON:
|
|
51514
|
+
row = {'courseId': courseId, 'courseName': course['name'],
|
|
51515
|
+
'studentGroupId': studentGroupId, 'studentGroupTitle': studentGroup['title']}
|
|
51516
|
+
for member in students:
|
|
51517
|
+
csvPF.WriteRowTitles(flattenJSON(member, flattened=row.copy()))
|
|
51518
|
+
else:
|
|
51519
|
+
row = {'courseId': courseId, 'courseName': course['name'],
|
|
51520
|
+
'studentGroupId': studentGroupId, 'studentGroupTitle': studentGroup['title']}
|
|
51521
|
+
row['JSON'] = json.dumps(list(students))
|
|
51522
|
+
csvPF.WriteRowNoFilter(row)
|
|
51523
|
+
if showItemCountOnly:
|
|
51524
|
+
writeStdout(f'{itemCount}\n')
|
|
51525
|
+
return
|
|
51526
|
+
if not showMembers:
|
|
51527
|
+
title = 'Course Student Groups'
|
|
51528
|
+
else:
|
|
51529
|
+
title = 'Course Student Group Members'
|
|
51530
|
+
csvPF.writeCSVfile(title)
|
|
51531
|
+
|
|
51532
|
+
# gam create course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
|
51533
|
+
# gam delete course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
|
51534
|
+
# gam sync course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
|
51535
|
+
# gam clear course-studentgroup-members <CourseID> <StudentGroupID>
|
|
51536
|
+
def doProcessCourseStudentGroupMembers():
|
|
51537
|
+
def _getCurrentStudents():
|
|
51538
|
+
printGettingEntityItemForWhom(Ent.USER, Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId)
|
|
51539
|
+
pageMessage = getPageMessage()
|
|
51540
|
+
try:
|
|
51541
|
+
return callGAPIpages(ocroom.courses().studentGroups().studentGroupMembers(), 'list', 'studentGroupMembers',
|
|
51542
|
+
pageMessage=pageMessage,
|
|
51543
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
|
51544
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51545
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51546
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51547
|
+
courseId=courseId, studentGroupId=studentGroupId)
|
|
51548
|
+
except GAPI.notFound as e:
|
|
51549
|
+
entityActionFailedWarning([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
|
|
51550
|
+
return []
|
|
51551
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51552
|
+
entityActionFailedExit([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
|
|
51553
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51554
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51555
|
+
|
|
51556
|
+
def _getStudentUserId(kvList, student, i, count):
|
|
51557
|
+
normalizedEmailAddressOrUID = normalizeEmailAddressOrUID(student)
|
|
51558
|
+
if normalizedEmailAddressOrUID.find('@') == -1:
|
|
51559
|
+
return normalizedEmailAddressOrUID
|
|
51560
|
+
try:
|
|
51561
|
+
return callGAPI(cd.users(), 'get',
|
|
51562
|
+
throwReasons=GAPI.USER_GET_THROW_REASONS,
|
|
51563
|
+
userKey=normalizedEmailAddressOrUID, fields='id')['id']
|
|
51564
|
+
except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
|
|
51565
|
+
GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
|
|
51566
|
+
entityActionFailedWarning(kvList, str(e), i, count)
|
|
51567
|
+
return None
|
|
51568
|
+
|
|
51569
|
+
def _processStudent(function, kvList, kwargs, i, count):
|
|
51570
|
+
try:
|
|
51571
|
+
callGAPI(ocroom.courses().studentGroups().studentGroupMembers(), function,
|
|
51572
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.ALREADY_EXISTS,
|
|
51573
|
+
GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
|
|
51574
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51575
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51576
|
+
previewVersion='V1_20250630_PREVIEW',
|
|
51577
|
+
**kwargs)
|
|
51578
|
+
entityActionPerformed(kvList, i, count)
|
|
51579
|
+
except (GAPI.alreadyExists, GAPI.notFound) as e:
|
|
51580
|
+
entityActionFailedWarning(kvList, str(e), i, count)
|
|
51581
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51582
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51583
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51584
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51585
|
+
|
|
51586
|
+
def _addStudents(students, getUserIds):
|
|
51587
|
+
count = len(students)
|
|
51588
|
+
i = 0
|
|
51589
|
+
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
|
|
51590
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
|
|
51591
|
+
kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'body': {'userId': ''}}
|
|
51592
|
+
for student in students:
|
|
51593
|
+
i += 1
|
|
51594
|
+
if getUserIds:
|
|
51595
|
+
userId = _getStudentUserId(kvList, student, i, count)
|
|
51596
|
+
if userId is None:
|
|
51597
|
+
continue
|
|
51598
|
+
kvList[-1] = student
|
|
51599
|
+
else:
|
|
51600
|
+
userId = student
|
|
51601
|
+
kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
|
|
51602
|
+
kwargs['body']['userId'] = userId
|
|
51603
|
+
_processStudent('create', kvList, kwargs, i, count)
|
|
51604
|
+
|
|
51605
|
+
def _removeStudents(students, getUserIds):
|
|
51606
|
+
count = len(students)
|
|
51607
|
+
i = 0
|
|
51608
|
+
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
|
|
51609
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
|
|
51610
|
+
kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'userId': ''}
|
|
51611
|
+
for student in students:
|
|
51612
|
+
i += 1
|
|
51613
|
+
if getUserIds:
|
|
51614
|
+
userId = _getStudentUserId(kvList, student, i, count)
|
|
51615
|
+
if userId is None:
|
|
51616
|
+
continue
|
|
51617
|
+
kvList[-1] = student
|
|
51618
|
+
else:
|
|
51619
|
+
userId = student
|
|
51620
|
+
kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
|
|
51621
|
+
kwargs['userId'] = userId
|
|
51622
|
+
_processStudent('delete', kvList, kwargs, i, count)
|
|
51623
|
+
|
|
51624
|
+
croom = buildGAPIObject(API.CLASSROOM)
|
|
51625
|
+
cd = buildGAPIObject(API.DIRECTORY)
|
|
51626
|
+
action = Act.Get()
|
|
51627
|
+
courseId = getString(Cmd.OB_COURSE_ID)
|
|
51628
|
+
studentGroupId = getString(Cmd.OB_STUDENTGROUP_ID)
|
|
51629
|
+
if action != Act.CLEAR:
|
|
51630
|
+
_, clStudents = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, groupMemberType=Ent.TYPE_USER)
|
|
51631
|
+
clStudents = [normalizeEmailAddressOrUID(student) for student in clStudents]
|
|
51632
|
+
checkForExtraneousArguments()
|
|
51633
|
+
_, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
|
51634
|
+
if count == 0:
|
|
51635
|
+
return
|
|
51636
|
+
ocroom = coursesInfo[courseId]['croom']
|
|
51637
|
+
courseId = coursesInfo[courseId]['id']
|
|
51638
|
+
if action in {Act.SYNC, Act.CLEAR}:
|
|
51639
|
+
currentStudents = [student['userId'] for student in _getCurrentStudents()]
|
|
51640
|
+
if action == Act.CLEAR:
|
|
51641
|
+
_removeStudents(currentStudents, False)
|
|
51642
|
+
elif action == Act.DELETE:
|
|
51643
|
+
_removeStudents(clStudents, True)
|
|
51644
|
+
elif action in {Act.ADD, Act.CREATE}:
|
|
51645
|
+
_addStudents(clStudents, True)
|
|
51646
|
+
else: # elif action == Act.SYNC:
|
|
51647
|
+
currentMembersSet = set(currentStudents)
|
|
51648
|
+
syncMembersSet = set()
|
|
51649
|
+
count = len(clStudents)
|
|
51650
|
+
i = 0
|
|
51651
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
|
|
51652
|
+
for student in clStudents:
|
|
51653
|
+
i += 1
|
|
51654
|
+
kvList[-1] = student
|
|
51655
|
+
userId = _getStudentUserId(kvList, student, i, count)
|
|
51656
|
+
if userId is None:
|
|
51657
|
+
continue
|
|
51658
|
+
syncMembersSet.add(userId)
|
|
51659
|
+
removeStudentsSet = currentMembersSet-syncMembersSet
|
|
51660
|
+
addStudentsSet = syncMembersSet-currentMembersSet
|
|
51661
|
+
Act.Set(Act.DELETE)
|
|
51662
|
+
_removeStudents(removeStudentsSet, False)
|
|
51663
|
+
Act.Set(Act.ADD)
|
|
51664
|
+
_addStudents(addStudentsSet, False)
|
|
51665
|
+
|
|
51666
|
+
# gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
|
|
51667
|
+
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
51668
|
+
# [showitemcountonly] [formatjson [quotechar <Character>]]
|
|
51669
|
+
def doPrintCourseStudentGroupMembers():
|
|
51670
|
+
doPrintCourseStudentGroups(showMembers=True)
|
|
51671
|
+
|
|
51212
51672
|
def _showASPs(user, asps, i=0, count=0):
|
|
51213
51673
|
Act.Set(Act.SHOW)
|
|
51214
51674
|
jcount = len(asps)
|
|
@@ -77337,6 +77797,8 @@ MAIN_ADD_CREATE_FUNCTIONS = {
|
|
|
77337
77797
|
Cmd.ARG_CIGROUP: doCreateCIGroup,
|
|
77338
77798
|
Cmd.ARG_CONTACT: doCreateDomainContact,
|
|
77339
77799
|
Cmd.ARG_COURSE: doCreateCourse,
|
|
77800
|
+
Cmd.ARG_COURSESTUDENTGROUP: doCreateCourseStudentGroups,
|
|
77801
|
+
Cmd.ARG_COURSESTUDENTGROUPMEMBERS: doProcessCourseStudentGroupMembers,
|
|
77340
77802
|
Cmd.ARG_DATATRANSFER: doCreateDataTransfer,
|
|
77341
77803
|
Cmd.ARG_DEVICE: doCreateCIDevice,
|
|
77342
77804
|
Cmd.ARG_DOMAIN: doCreateDomain,
|
|
@@ -77412,6 +77874,8 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|
|
77412
77874
|
(Act.CLEAR,
|
|
77413
77875
|
{Cmd.ARG_ALERTSETTINGS: doClearAlertSettings,
|
|
77414
77876
|
Cmd.ARG_CONTACT: doClearDomainContacts,
|
|
77877
|
+
Cmd.ARG_COURSESTUDENTGROUP: doClearCourseStudentGroups,
|
|
77878
|
+
Cmd.ARG_COURSESTUDENTGROUPMEMBERS: doProcessCourseStudentGroupMembers,
|
|
77415
77879
|
}
|
|
77416
77880
|
),
|
|
77417
77881
|
'close':
|
|
@@ -77454,6 +77918,8 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|
|
77454
77918
|
Cmd.ARG_CONTACTPHOTO: doDeleteDomainContactPhoto,
|
|
77455
77919
|
Cmd.ARG_COURSE: doDeleteCourse,
|
|
77456
77920
|
Cmd.ARG_COURSES: doDeleteCourses,
|
|
77921
|
+
Cmd.ARG_COURSESTUDENTGROUP: doDeleteCourseStudentGroups,
|
|
77922
|
+
Cmd.ARG_COURSESTUDENTGROUPMEMBERS: doProcessCourseStudentGroupMembers,
|
|
77457
77923
|
Cmd.ARG_DEVICE: doDeleteCIDevice,
|
|
77458
77924
|
Cmd.ARG_DEVICEUSER: doDeleteCIDeviceUser,
|
|
77459
77925
|
Cmd.ARG_DOMAIN: doDeleteDomain,
|
|
@@ -77631,6 +78097,8 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|
|
77631
78097
|
Cmd.ARG_COURSEANNOUNCEMENTS: doPrintCourseAnnouncements,
|
|
77632
78098
|
Cmd.ARG_COURSEMATERIALS: doPrintCourseMaterials,
|
|
77633
78099
|
Cmd.ARG_COURSEPARTICIPANTS: doPrintCourseParticipants,
|
|
78100
|
+
Cmd.ARG_COURSESTUDENTGROUP: doPrintCourseStudentGroups,
|
|
78101
|
+
Cmd.ARG_COURSESTUDENTGROUPMEMBERS: doPrintCourseStudentGroupMembers,
|
|
77634
78102
|
Cmd.ARG_COURSESUBMISSIONS: doPrintCourseSubmissions,
|
|
77635
78103
|
Cmd.ARG_COURSETOPICS: doPrintCourseTopics,
|
|
77636
78104
|
Cmd.ARG_COURSEWORK: doPrintCourseWork,
|
|
@@ -77815,6 +78283,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|
|
77815
78283
|
(Act.SYNC,
|
|
77816
78284
|
{Cmd.ARG_DEVICE: doSyncCIDevices,
|
|
77817
78285
|
Cmd.ARG_SHAREDDRIVEACLS: copySyncSharedDriveACLs,
|
|
78286
|
+
Cmd.ARG_COURSESTUDENTGROUPMEMBERS: doProcessCourseStudentGroupMembers,
|
|
77818
78287
|
}
|
|
77819
78288
|
),
|
|
77820
78289
|
'unhide':
|
|
@@ -77837,6 +78306,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
|
|
77837
78306
|
Cmd.ARG_CONTACTPHOTO: doUpdateDomainContactPhoto,
|
|
77838
78307
|
Cmd.ARG_COURSE: doUpdateCourse,
|
|
77839
78308
|
Cmd.ARG_COURSES: doUpdateCourses,
|
|
78309
|
+
Cmd.ARG_COURSESTUDENTGROUP: doUpdateCourseStudentGroups,
|
|
77840
78310
|
Cmd.ARG_CROS: doUpdateCrOSDevices,
|
|
77841
78311
|
Cmd.ARG_CUSTOMER: doUpdateCustomer,
|
|
77842
78312
|
Cmd.ARG_DEVICE: doUpdateCIDevice,
|
|
@@ -77954,6 +78424,7 @@ MAIN_COMMANDS_OBJ_ALIASES = {
|
|
|
77954
78424
|
Cmd.ARG_CLASSROOMINVITATIONS: Cmd.ARG_CLASSROOMINVITATION,
|
|
77955
78425
|
Cmd.ARG_CONTACTS: Cmd.ARG_CONTACT,
|
|
77956
78426
|
Cmd.ARG_CONTACTPHOTOS: Cmd.ARG_CONTACTPHOTO,
|
|
78427
|
+
Cmd.ARG_COURSESTUDENTGROUPS: Cmd.ARG_COURSESTUDENTGROUP,
|
|
77957
78428
|
Cmd.ARG_CROSES: Cmd.ARG_CROS,
|
|
77958
78429
|
Cmd.ARG_DATATRANSFERS: Cmd.ARG_DATATRANSFER,
|
|
77959
78430
|
Cmd.ARG_DEVICES: Cmd.ARG_DEVICE,
|
gam/gamlib/glcfg.py
CHANGED
|
@@ -145,6 +145,8 @@ CSV_OUTPUT_USERS_AUDIT = 'csv_output_users_audit'
|
|
|
145
145
|
CUSTOMER_ID = 'customer_id'
|
|
146
146
|
# If debug_level > 0: extra_args['prettyPrint'] = True, httplib2.debuglevel = gam_debug_level, appsObj.debug = True
|
|
147
147
|
DEBUG_LEVEL = 'debug_level'
|
|
148
|
+
# Developer Preview API Key
|
|
149
|
+
DEVELOPER_PREVIEW_API_KEY = 'developer_preview_api_key'
|
|
148
150
|
# When retrieving lists of ChromeOS devices from API, how many should be retrieved in each chunk
|
|
149
151
|
DEVICE_MAX_RESULTS = 'device_max_results'
|
|
150
152
|
# Domain obtained from gam.cfg or oauth2.txt
|
|
@@ -370,6 +372,7 @@ Defaults = {
|
|
|
370
372
|
CSV_OUTPUT_USERS_AUDIT: FALSE,
|
|
371
373
|
CUSTOMER_ID: MY_CUSTOMER,
|
|
372
374
|
DEBUG_LEVEL: '0',
|
|
375
|
+
DEVELOPER_PREVIEW_API_KEY: '',
|
|
373
376
|
DEVICE_MAX_RESULTS: '200',
|
|
374
377
|
DOMAIN: '',
|
|
375
378
|
DRIVE_DIR: '',
|
|
@@ -536,6 +539,7 @@ VAR_INFO = {
|
|
|
536
539
|
CSV_OUTPUT_USERS_AUDIT: {VAR_TYPE: TYPE_BOOLEAN},
|
|
537
540
|
CUSTOMER_ID: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'CUSTOMER_ID', VAR_LIMITS: (0, None)},
|
|
538
541
|
DEBUG_LEVEL: {VAR_TYPE: TYPE_INTEGER, VAR_SIGFILE: 'debug.gam', VAR_LIMITS: (0, None), VAR_SFFT: ('0', '4')},
|
|
542
|
+
DEVELOPER_PREVIEW_API_KEY: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
|
|
539
543
|
DEVICE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)},
|
|
540
544
|
DOMAIN: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GA_DOMAIN', VAR_LIMITS: (0, None)},
|
|
541
545
|
DRIVE_DIR: {VAR_TYPE: TYPE_DIRECTORY, VAR_ENVVAR: 'GAMDRIVEDIR'},
|
gam/gamlib/glclargs.py
CHANGED
|
@@ -528,6 +528,9 @@ class GamCLArgs():
|
|
|
528
528
|
ARG_COURSEANNOUNCEMENTS = 'courseannouncements'
|
|
529
529
|
ARG_COURSEMATERIALS = 'coursematerials'
|
|
530
530
|
ARG_COURSEPARTICIPANTS = 'courseparticipants'
|
|
531
|
+
ARG_COURSESTUDENTGROUP = 'coursestudentgroup'
|
|
532
|
+
ARG_COURSESTUDENTGROUPS = 'coursestudentgroups'
|
|
533
|
+
ARG_COURSESTUDENTGROUPMEMBERS = 'coursestudentgroupmembers'
|
|
531
534
|
ARG_COURSESUBMISSIONS = 'coursesubmissions'
|
|
532
535
|
ARG_COURSETOPICS = 'coursetopics'
|
|
533
536
|
ARG_COURSEWORK = 'coursework'
|
|
@@ -1055,6 +1058,8 @@ class GamCLArgs():
|
|
|
1055
1058
|
OB_STATE_NAME_LIST = "StateNameList"
|
|
1056
1059
|
OB_STRING = 'String'
|
|
1057
1060
|
OB_STRING_LIST = 'StringList'
|
|
1061
|
+
OB_STUDENTGROUP_ID = 'StudentGroupID'
|
|
1062
|
+
OB_STUDENTGROUP_ID_ENTITY = 'StudentGroupIDEntity'
|
|
1058
1063
|
OB_STUDENT_ITEM = 'StudentItem'
|
|
1059
1064
|
OB_TAG = 'Tag'
|
|
1060
1065
|
OB_TAGMANAGER_PATH_LIST = 'TagManagerPathList'
|
gam/gamlib/glentity.py
CHANGED
|
@@ -155,6 +155,8 @@ class GamEntity():
|
|
|
155
155
|
COURSE_MATERIAL_STATE = 'cmst'
|
|
156
156
|
COURSE_NAME = 'cona'
|
|
157
157
|
COURSE_STATE = 'cost'
|
|
158
|
+
COURSE_STUDENTGROUP = 'cosg'
|
|
159
|
+
COURSE_STUDENTGROUP_MEMBER = 'csgm'
|
|
158
160
|
COURSE_SUBMISSION_ID = 'csid'
|
|
159
161
|
COURSE_SUBMISSION_STATE = 'csst'
|
|
160
162
|
COURSE_TOPIC = 'ctop'
|
|
@@ -517,6 +519,8 @@ class GamEntity():
|
|
|
517
519
|
COURSE_MATERIAL_STATE: ['Course Material States', 'Course Material State'],
|
|
518
520
|
COURSE_NAME: ['Course Names', 'Course Name'],
|
|
519
521
|
COURSE_STATE: ['Course States', 'Course State'],
|
|
522
|
+
COURSE_STUDENTGROUP: ['Course Student Groups', 'Course Student Group'],
|
|
523
|
+
COURSE_STUDENTGROUP_MEMBER: ['Course Student Group Members', 'Course Student Group Member'],
|
|
520
524
|
COURSE_SUBMISSION_ID: ['Course Submission IDs', 'Course Submission ID'],
|
|
521
525
|
COURSE_SUBMISSION_STATE: ['Course Submission States', 'Course Submission State'],
|
|
522
526
|
COURSE_TOPIC: ['Course Topics', 'Course Topic'],
|
gam/gamlib/glglobals.py
CHANGED
|
@@ -31,6 +31,8 @@ API_CALLS_RETRY_DATA = 'rtry'
|
|
|
31
31
|
CACHE_DIR = 'gacd'
|
|
32
32
|
# Reset GAM cache directory after discovery
|
|
33
33
|
CACHE_DISCOVERY_ONLY = 'gcdo'
|
|
34
|
+
# Classroom owner service object
|
|
35
|
+
CLASSROOM_OWNER_SA = 'cosa'
|
|
34
36
|
# Classroom service not available
|
|
35
37
|
CLASSROOM_SERVICE_NOT_AVAILABLE = 'csna'
|
|
36
38
|
# Command logging
|
|
@@ -221,6 +223,7 @@ Globals = {
|
|
|
221
223
|
API_CALLS_RETRY_DATA: {},
|
|
222
224
|
CACHE_DIR: None,
|
|
223
225
|
CACHE_DISCOVERY_ONLY: True,
|
|
226
|
+
CLASSROOM_OWNER_SA: {},
|
|
224
227
|
CLASSROOM_SERVICE_NOT_AVAILABLE: False,
|
|
225
228
|
CMDLOG_HANDLER: None,
|
|
226
229
|
CMDLOG_LOGGER: None,
|
gam/gamlib/glmsgs.py
CHANGED
|
@@ -53,7 +53,7 @@ Please go to:
|
|
|
53
53
|
5. Click "NEXT"
|
|
54
54
|
6. Under "Audience", choose INTERNAL
|
|
55
55
|
7. Click "NEXT"
|
|
56
|
-
8. Under, "Contact Information", enter
|
|
56
|
+
8. Under, "Contact Information", enter {2} or another value in "Email addresses *"
|
|
57
57
|
9. Click "NEXT"
|
|
58
58
|
10. Under "Finish", click "I agree to the Google API Services: User Data Policy."
|
|
59
59
|
11. Click "CONTINUE"
|
gam/googleapiclient/version.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
gam/__init__.py,sha256=
|
|
1
|
+
gam/__init__.py,sha256=A7MFQZo7V4ATMe6INRM3Lkc_ci1la6zTZc8xL6GSbtk,3607451
|
|
2
2
|
gam/__main__.py,sha256=amz0-959ph6zkZKqjaar4n60yho-T37w6qWI36qx0CA,1049
|
|
3
3
|
gam/cacerts.pem,sha256=DUsVo2XlFYwfkhe3gnxa-Km4Z4noz74hSApXwTT-nQE,44344
|
|
4
4
|
gam/cbcm-v1.1beta1.json,sha256=xO5XloCQQULmPbFBx5bckdqmbLFQ7sJ2TImhE1ysDIY,19439
|
|
@@ -24,14 +24,14 @@ gam/atom/url.py,sha256=pxO1TlORxyKQTQ1bkBE1unFzjnv9c8LjJkm-UEORShY,4276
|
|
|
24
24
|
gam/gamlib/__init__.py,sha256=z5mF-y0j8pm-YNFBaiuxB4M_GAUPG-cXWwrhYwrVReM,679
|
|
25
25
|
gam/gamlib/glaction.py,sha256=1Il_HrChVnPkzZwiZs5au4mFQVtq4K1Z42uIuR6qdnI,9419
|
|
26
26
|
gam/gamlib/glapi.py,sha256=u97M7Y2BeP3tYEEGYEz-9kY4fdV0fYkeqC3YN-sRwNc,36028
|
|
27
|
-
gam/gamlib/glcfg.py,sha256=
|
|
28
|
-
gam/gamlib/glclargs.py,sha256=
|
|
29
|
-
gam/gamlib/glentity.py,sha256=
|
|
27
|
+
gam/gamlib/glcfg.py,sha256=7Ut-7sDTw-WVHZfvDWn_dlVNfuWd6VsPDBpQ3qnyzJE,28100
|
|
28
|
+
gam/gamlib/glclargs.py,sha256=9Oze97BT_GS2WXf4LYg4JlSCmZ_8fG2a33Ft1_pX43k,44134
|
|
29
|
+
gam/gamlib/glentity.py,sha256=8F98YR1ronheiQShD6WHlY-YnBKfMDrc33iRuRoLIvo,35097
|
|
30
30
|
gam/gamlib/glgapi.py,sha256=pdBbwNtnCwFWxJGaP-_3hdTjSNoOCJF2yo76WdQOi1k,40426
|
|
31
31
|
gam/gamlib/glgdata.py,sha256=weRppttWm6uRyqtBoGPKoHiNZ2h28nhfUV4J_mbCszY,2707
|
|
32
|
-
gam/gamlib/glglobals.py,sha256=
|
|
32
|
+
gam/gamlib/glglobals.py,sha256=oJfaLUQj46XqwrOzRfWhGqO0f1P26xjJZefaILJUFGE,9695
|
|
33
33
|
gam/gamlib/glindent.py,sha256=RfBa2LDfLIqPLL5vMfC689TCVmqn8xf-qulSzkiatrc,1228
|
|
34
|
-
gam/gamlib/glmsgs.py,sha256=
|
|
34
|
+
gam/gamlib/glmsgs.py,sha256=uluaFxw5YCG1so9uvOYU6HvAwGJNqJcB1curD8hH-G0,34001
|
|
35
35
|
gam/gamlib/glskus.py,sha256=e1u3zw1MGQjBgAFXqjrGWQl2d7eYpVlMYGpIKNwjskQ,15360
|
|
36
36
|
gam/gamlib/gluprop.py,sha256=IyPLCyvn7-NHTUenM71YPQPXRZXx6CB5q-GtJ-FYd1c,11461
|
|
37
37
|
gam/gamlib/glverlibs.py,sha256=xoQXiwcE_-HVYKv-VYA8O0mazRsc9mN-_ysj1dAlMyc,992
|
|
@@ -58,15 +58,15 @@ gam/googleapiclient/http.py,sha256=ITE51oqDBqN1-AA5D-Tnlj3egGc_5O0V5xSzBw3UTKI,6
|
|
|
58
58
|
gam/googleapiclient/mimeparse.py,sha256=wwouQMCjppTocJtiQhkkTa27kocYwlFRALL2z11Xo1Y,6530
|
|
59
59
|
gam/googleapiclient/model.py,sha256=NQDO1GhOGNVCJlSSCLOecdA11yf8RDXfSLFxYb3R7EE,14085
|
|
60
60
|
gam/googleapiclient/schema.py,sha256=rR3u8WPQ_V8a7GCUsNuvtf6GxzwuMO0HaqsTBp3tnyM,10414
|
|
61
|
-
gam/googleapiclient/version.py,sha256=
|
|
61
|
+
gam/googleapiclient/version.py,sha256=CQnalMsxpdK1_gw_iADQK3D0RNBQ2vMlzw3PbyNFWC4,599
|
|
62
62
|
gam/googleapiclient/discovery_cache/__init__.py,sha256=ww_vl0vhVLuHSEdRTv3-gq6EDG--Ff7rILYHHFifnzc,2315
|
|
63
63
|
gam/googleapiclient/discovery_cache/appengine_memcache.py,sha256=6T1pQj-toAhDwfgLuiggFGhxKNGw5y-NnLUzLIF_M4s,1657
|
|
64
64
|
gam/googleapiclient/discovery_cache/base.py,sha256=yCDPtxnbNN-p5_9fzBacC6P3wcUPlaCQIy5v_dXTons,1389
|
|
65
65
|
gam/googleapiclient/discovery_cache/file_cache.py,sha256=sim3Mg4HgRYo3vX75jvcKy_aV568EvIrtBfvfbw-044,4774
|
|
66
66
|
gam/iso8601/__init__.py,sha256=Z2PsYbXgAH5a5xzUvgczCboPzqWpm65kRcIngCnhViU,1218
|
|
67
67
|
gam/iso8601/iso8601.py,sha256=Li2FHZ4sBTWuthuQhyCvmvj0j6At8JbGzkSv2fc2RHU,4384
|
|
68
|
-
gam7-7.
|
|
69
|
-
gam7-7.
|
|
70
|
-
gam7-7.
|
|
71
|
-
gam7-7.
|
|
72
|
-
gam7-7.
|
|
68
|
+
gam7-7.20.0.dist-info/METADATA,sha256=muNbkdkJZBuXH9QFD5Q_BGC8FQETAtB2kH6QwP5RPDc,2940
|
|
69
|
+
gam7-7.20.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
70
|
+
gam7-7.20.0.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
|
|
71
|
+
gam7-7.20.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
72
|
+
gam7-7.20.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|