gam7 7.20.2__py3-none-any.whl → 7.20.4__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 +129 -102
- gam/{iso8601/iso8601.py → gamlib/gliso8601.py} +7 -8
- gam/gamlib/glmsgs.py +1 -0
- gam/gamlib/glskus.py +1 -1
- {gam7-7.20.2.dist-info → gam7-7.20.4.dist-info}/METADATA +1 -1
- {gam7-7.20.2.dist-info → gam7-7.20.4.dist-info}/RECORD +9 -26
- gam/googleapiclient/__init__.py +0 -27
- gam/googleapiclient/_auth.py +0 -167
- gam/googleapiclient/_helpers.py +0 -207
- gam/googleapiclient/channel.py +0 -315
- gam/googleapiclient/discovery.py +0 -1662
- gam/googleapiclient/discovery_cache/__init__.py +0 -78
- gam/googleapiclient/discovery_cache/appengine_memcache.py +0 -55
- gam/googleapiclient/discovery_cache/base.py +0 -46
- gam/googleapiclient/discovery_cache/file_cache.py +0 -145
- gam/googleapiclient/errors.py +0 -197
- gam/googleapiclient/http.py +0 -1962
- gam/googleapiclient/mimeparse.py +0 -183
- gam/googleapiclient/model.py +0 -429
- gam/googleapiclient/schema.py +0 -317
- gam/googleapiclient/version.py +0 -15
- gam/iso8601/__init__.py +0 -28
- gam/six.py +0 -982
- {gam7-7.20.2.dist-info → gam7-7.20.4.dist-info}/WHEEL +0 -0
- {gam7-7.20.2.dist-info → gam7-7.20.4.dist-info}/entry_points.txt +0 -0
- {gam7-7.20.2.dist-info → gam7-7.20.4.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.20.
|
|
28
|
+
__version__ = '7.20.04'
|
|
29
29
|
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
|
30
30
|
|
|
31
31
|
#pylint: disable=wrong-import-position
|
|
@@ -120,6 +120,10 @@ from google.auth.jwt import Credentials as JWTCredentials
|
|
|
120
120
|
import google.oauth2.service_account
|
|
121
121
|
import google_auth_oauthlib.flow
|
|
122
122
|
import google_auth_httplib2
|
|
123
|
+
import googleapiclient
|
|
124
|
+
import googleapiclient.discovery
|
|
125
|
+
import googleapiclient.errors
|
|
126
|
+
import googleapiclient.http
|
|
123
127
|
import httplib2
|
|
124
128
|
|
|
125
129
|
httplib2.RETRIES = 5
|
|
@@ -139,6 +143,7 @@ from gamlib import glgapi as GAPI
|
|
|
139
143
|
from gamlib import glgdata as GDATA
|
|
140
144
|
from gamlib import glglobals as GM
|
|
141
145
|
from gamlib import glindent
|
|
146
|
+
from gamlib import gliso8601 as iso8601
|
|
142
147
|
from gamlib import glmsgs as Msg
|
|
143
148
|
from gamlib import glskus as SKU
|
|
144
149
|
from gamlib import gluprop as UProp
|
|
@@ -149,12 +154,6 @@ import gdata.apps.audit
|
|
|
149
154
|
import gdata.apps.audit.service
|
|
150
155
|
import gdata.apps.contacts
|
|
151
156
|
import gdata.apps.contacts.service
|
|
152
|
-
# Import local library, does not include discovery documents
|
|
153
|
-
import googleapiclient
|
|
154
|
-
import googleapiclient.discovery
|
|
155
|
-
import googleapiclient.errors
|
|
156
|
-
import googleapiclient.http
|
|
157
|
-
from iso8601 import iso8601
|
|
158
157
|
|
|
159
158
|
IS08601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S%:z'
|
|
160
159
|
RFC2822_TIME_FORMAT = '%a, %d %b %Y %H:%M:%S %z'
|
|
@@ -2013,11 +2012,11 @@ def getTimeOrDeltaFromNow(returnDateTime=False):
|
|
|
2013
2012
|
except OverflowError:
|
|
2014
2013
|
pass
|
|
2015
2014
|
try:
|
|
2016
|
-
fullDateTime
|
|
2015
|
+
fullDateTime = iso8601.parse_date(argstr)
|
|
2017
2016
|
Cmd.Advance()
|
|
2018
2017
|
if not returnDateTime:
|
|
2019
2018
|
return argstr.replace(' ', 'T')
|
|
2020
|
-
return (fullDateTime,
|
|
2019
|
+
return (fullDateTime, fullDateTime.tzinfo, argstr.replace(' ', 'T'))
|
|
2021
2020
|
except (iso8601.ParseError, OverflowError):
|
|
2022
2021
|
pass
|
|
2023
2022
|
invalidArgumentExit(YYYYMMDDTHHMMSS_FORMAT_REQUIRED)
|
|
@@ -2335,7 +2334,7 @@ def formatLocalTime(dateTimeStr):
|
|
|
2335
2334
|
if dateTimeStr in {NEVER_TIME, NEVER_TIME_NOMS}:
|
|
2336
2335
|
return GC.Values[GC.NEVER_TIME]
|
|
2337
2336
|
try:
|
|
2338
|
-
timestamp
|
|
2337
|
+
timestamp = iso8601.parse_date(dateTimeStr)
|
|
2339
2338
|
if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
|
|
2340
2339
|
if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]:
|
|
2341
2340
|
return ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE]))
|
|
@@ -3736,10 +3735,7 @@ def SetGlobalVariables():
|
|
|
3736
3735
|
if value and not os.path.isabs(value):
|
|
3737
3736
|
value = os.path.expanduser(os.path.join(_getCfgDirectory(sectionName, GC.CONFIG_DIR), value))
|
|
3738
3737
|
elif not value and itemName == GC.CACERTS_PEM:
|
|
3739
|
-
|
|
3740
|
-
value = os.path.join(sys._MEIPASS, GC.FN_CACERTS_PEM) #pylint: disable=no-member
|
|
3741
|
-
else:
|
|
3742
|
-
value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
|
|
3738
|
+
value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
|
|
3743
3739
|
return value
|
|
3744
3740
|
|
|
3745
3741
|
def _readGamCfgFile(config, fileName):
|
|
@@ -7436,7 +7432,7 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
|
|
|
7436
7432
|
return None
|
|
7437
7433
|
else:
|
|
7438
7434
|
try:
|
|
7439
|
-
rowTime
|
|
7435
|
+
rowTime = iso8601.parse_date(rowDate)
|
|
7440
7436
|
except (iso8601.ParseError, OverflowError):
|
|
7441
7437
|
return None
|
|
7442
7438
|
return ISOformatTimeStamp(datetime.datetime(rowTime.year, rowTime.month, rowTime.day, tzinfo=iso8601.UTC))
|
|
@@ -7501,7 +7497,7 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
|
|
|
7501
7497
|
if YYYYMMDD_PATTERN.match(rowDate):
|
|
7502
7498
|
return None
|
|
7503
7499
|
try:
|
|
7504
|
-
rowTime
|
|
7500
|
+
rowTime = iso8601.parse_date(rowDate)
|
|
7505
7501
|
except (iso8601.ParseError, OverflowError):
|
|
7506
7502
|
return None
|
|
7507
7503
|
return f'{rowTime.hour:02d}:{rowTime.minute:02d}'
|
|
@@ -12413,7 +12409,7 @@ def checkServiceAccount(users):
|
|
|
12413
12409
|
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.NOT_FOUND,
|
|
12414
12410
|
GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
|
12415
12411
|
name=name, fields='validAfterTime')
|
|
12416
|
-
key_created
|
|
12412
|
+
key_created = iso8601.parse_date(key['validAfterTime'])
|
|
12417
12413
|
key_age = todaysTime()-key_created
|
|
12418
12414
|
printPassFail(Msg.SERVICE_ACCOUNT_PRIVATE_KEY_AGE.format(key_age.days), testWarn if key_age.days > 30 else testPass)
|
|
12419
12415
|
except GAPI.permissionDenied:
|
|
@@ -14368,7 +14364,7 @@ def doReport():
|
|
|
14368
14364
|
eventTime = activity.get('id', {}).get('time', UNKNOWN)
|
|
14369
14365
|
if eventTime != UNKNOWN:
|
|
14370
14366
|
try:
|
|
14371
|
-
eventTime
|
|
14367
|
+
eventTime = iso8601.parse_date(eventTime)
|
|
14372
14368
|
except (iso8601.ParseError, OverflowError):
|
|
14373
14369
|
eventTime = UNKNOWN
|
|
14374
14370
|
if eventTime != UNKNOWN:
|
|
@@ -23867,7 +23863,7 @@ def _filterDeviceFiles(cros, selected, listLimit, startTime, endTime):
|
|
|
23867
23863
|
filteredItems = []
|
|
23868
23864
|
i = 0
|
|
23869
23865
|
for item in cros.get('deviceFiles', []):
|
|
23870
|
-
timeValue
|
|
23866
|
+
timeValue = iso8601.parse_date(item['createTime'])
|
|
23871
23867
|
if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
|
|
23872
23868
|
item['createTime'] = formatLocalTime(item['createTime'])
|
|
23873
23869
|
filteredItems.append(item)
|
|
@@ -23884,7 +23880,7 @@ def _filterCPUStatusReports(cros, selected, listLimit, startTime, endTime):
|
|
|
23884
23880
|
filteredItems = []
|
|
23885
23881
|
i = 0
|
|
23886
23882
|
for item in cros.get('cpuStatusReports', []):
|
|
23887
|
-
timeValue
|
|
23883
|
+
timeValue = iso8601.parse_date(item['reportTime'])
|
|
23888
23884
|
if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
|
|
23889
23885
|
item['reportTime'] = formatLocalTime(item['reportTime'])
|
|
23890
23886
|
for tempInfo in item.get('cpuTemperatureInfo', []):
|
|
@@ -23905,7 +23901,7 @@ def _filterSystemRamFreeReports(cros, selected, listLimit, startTime, endTime):
|
|
|
23905
23901
|
filteredItems = []
|
|
23906
23902
|
i = 0
|
|
23907
23903
|
for item in cros.get('systemRamFreeReports', []):
|
|
23908
|
-
timeValue
|
|
23904
|
+
timeValue = iso8601.parse_date(item['reportTime'])
|
|
23909
23905
|
if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
|
|
23910
23906
|
item['reportTime'] = formatLocalTime(item['reportTime'])
|
|
23911
23907
|
item['systemRamFreeInfo'] = ','.join([str(x) for x in item['systemRamFreeInfo']])
|
|
@@ -23938,7 +23934,7 @@ def _filterScreenshotFiles(cros, selected, listLimit, startTime, endTime):
|
|
|
23938
23934
|
filteredItems = []
|
|
23939
23935
|
i = 0
|
|
23940
23936
|
for item in cros.get('screenshotFiles', []):
|
|
23941
|
-
timeValue
|
|
23937
|
+
timeValue = iso8601.parse_date(item['createTime'])
|
|
23942
23938
|
if ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime)):
|
|
23943
23939
|
item['createTime'] = formatLocalTime(item['createTime'])
|
|
23944
23940
|
filteredItems.append(item)
|
|
@@ -24386,7 +24382,7 @@ def getDeviceFilesEntity():
|
|
|
24386
24382
|
else:
|
|
24387
24383
|
for timeItem in myarg.split(','):
|
|
24388
24384
|
try:
|
|
24389
|
-
timestamp
|
|
24385
|
+
timestamp = iso8601.parse_date(timeItem)
|
|
24390
24386
|
deviceFilesEntity['list'].append(ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE])))
|
|
24391
24387
|
except (iso8601.ParseError, OverflowError):
|
|
24392
24388
|
Cmd.Backup()
|
|
@@ -24415,14 +24411,14 @@ def _selectDeviceFiles(deviceId, deviceFiles, deviceFilesEntity):
|
|
|
24415
24411
|
count = 0
|
|
24416
24412
|
if deviceFilesEntity['time'][0] == 'before':
|
|
24417
24413
|
for deviceFile in deviceFiles:
|
|
24418
|
-
createTime
|
|
24414
|
+
createTime = iso8601.parse_date(deviceFile['createTime'])
|
|
24419
24415
|
if createTime >= dateTime:
|
|
24420
24416
|
break
|
|
24421
24417
|
count += 1
|
|
24422
24418
|
return deviceFiles[:count]
|
|
24423
24419
|
# if deviceFilesEntity['time'][0] == 'after':
|
|
24424
24420
|
for deviceFile in deviceFiles:
|
|
24425
|
-
createTime
|
|
24421
|
+
createTime = iso8601.parse_date(deviceFile['createTime'])
|
|
24426
24422
|
if createTime >= dateTime:
|
|
24427
24423
|
break
|
|
24428
24424
|
count += 1
|
|
@@ -24431,14 +24427,14 @@ def _selectDeviceFiles(deviceId, deviceFiles, deviceFilesEntity):
|
|
|
24431
24427
|
dateTime = deviceFilesEntity['range'][1]
|
|
24432
24428
|
spos = 0
|
|
24433
24429
|
for deviceFile in deviceFiles:
|
|
24434
|
-
createTime
|
|
24430
|
+
createTime = iso8601.parse_date(deviceFile['createTime'])
|
|
24435
24431
|
if createTime >= dateTime:
|
|
24436
24432
|
break
|
|
24437
24433
|
spos += 1
|
|
24438
24434
|
dateTime = deviceFilesEntity['range'][2]
|
|
24439
24435
|
epos = spos
|
|
24440
24436
|
for deviceFile in deviceFiles[spos:]:
|
|
24441
|
-
createTime
|
|
24437
|
+
createTime = iso8601.parse_date(deviceFile['createTime'])
|
|
24442
24438
|
if createTime >= dateTime:
|
|
24443
24439
|
break
|
|
24444
24440
|
epos += 1
|
|
@@ -25221,7 +25217,7 @@ def doInfoPrintShowCrOSTelemetry():
|
|
|
25221
25217
|
i = 0
|
|
25222
25218
|
for item in listItems:
|
|
25223
25219
|
if 'reportTime' in item:
|
|
25224
|
-
timeValue
|
|
25220
|
+
timeValue = iso8601.parse_date(item['reportTime'])
|
|
25225
25221
|
else:
|
|
25226
25222
|
timeValue = None
|
|
25227
25223
|
if (timeValue is None) or (((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime))):
|
|
@@ -40068,7 +40064,7 @@ def _getEventDaysOfWeek(event):
|
|
|
40068
40064
|
pass
|
|
40069
40065
|
elif 'dateTime' in event[attr]:
|
|
40070
40066
|
try:
|
|
40071
|
-
dateTime
|
|
40067
|
+
dateTime = iso8601.parse_date(event[attr]['dateTime'])
|
|
40072
40068
|
event[attr]['dayOfWeek'] = calendarlib.day_abbr[dateTime.weekday()]
|
|
40073
40069
|
except (iso8601.ParseError, OverflowError):
|
|
40074
40070
|
pass
|
|
@@ -48699,7 +48695,7 @@ def _courseItemPassesFilter(item, courseItemFilter):
|
|
|
48699
48695
|
return False
|
|
48700
48696
|
startTime = courseItemFilter['startTime']
|
|
48701
48697
|
endTime = courseItemFilter['endTime']
|
|
48702
|
-
timeValue
|
|
48698
|
+
timeValue = iso8601.parse_date(timeStr)
|
|
48703
48699
|
return ((startTime is None) or (timeValue >= startTime)) and ((endTime is None) or (timeValue <= endTime))
|
|
48704
48700
|
|
|
48705
48701
|
def _gettingCoursesQuery(courseSelectionParameters):
|
|
@@ -51247,7 +51243,7 @@ def doCreateCourseStudentGroups():
|
|
|
51247
51243
|
while Cmd.ArgumentsRemaining():
|
|
51248
51244
|
myarg = getArgument()
|
|
51249
51245
|
if myarg == 'title':
|
|
51250
|
-
titles.append(getString(Cmd.OB_STRING))
|
|
51246
|
+
titles.append(getString(Cmd.OB_STRING, maxLen=100))
|
|
51251
51247
|
elif myarg == 'select':
|
|
51252
51248
|
titles.extend(getEntityList(Cmd.OB_STRING_ENTITY, shlexSplit=True))
|
|
51253
51249
|
elif _getCourseSelectionParameters(myarg, courseSelectionParameters):
|
|
@@ -51450,8 +51446,26 @@ def doClearCourseStudentGroups():
|
|
|
51450
51446
|
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
51451
51447
|
# [showitemcountonly] [formatjson [quotechar <Character>]]
|
|
51452
51448
|
def doPrintCourseStudentGroups(showMembers=False):
|
|
51449
|
+
def _getCourseStudents():
|
|
51450
|
+
studentIdEmailMap = {}
|
|
51451
|
+
try:
|
|
51452
|
+
students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
|
|
51453
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
|
51454
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51455
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51456
|
+
courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
|
|
51457
|
+
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
|
51458
|
+
for student in students:
|
|
51459
|
+
studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress']
|
|
51460
|
+
except GAPI.notFound:
|
|
51461
|
+
pass
|
|
51462
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51463
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51464
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51465
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51466
|
+
return studentIdEmailMap
|
|
51467
|
+
|
|
51453
51468
|
croom = buildGAPIObject(API.CLASSROOM)
|
|
51454
|
-
cd = buildGAPIObject(API.DIRECTORY)
|
|
51455
51469
|
csvPF = CSVPrintFile(['courseId', 'courseName', 'studentGroupId', 'studentGroupTitle'])
|
|
51456
51470
|
FJQC = FormatJSONQuoteChar(csvPF)
|
|
51457
51471
|
courseSelectionParameters = _initCourseSelectionParameters()
|
|
@@ -51503,6 +51517,8 @@ def doPrintCourseStudentGroups(showMembers=False):
|
|
|
51503
51517
|
if not showMembers and showItemCountOnly:
|
|
51504
51518
|
itemCount += len(studentGroups)
|
|
51505
51519
|
continue
|
|
51520
|
+
if showMembers:
|
|
51521
|
+
studentIdEmailMap = _getCourseStudents()
|
|
51506
51522
|
for studentGroup in studentGroups:
|
|
51507
51523
|
studentGroupId = studentGroup['id']
|
|
51508
51524
|
if not showMembers:
|
|
@@ -51515,7 +51531,7 @@ def doPrintCourseStudentGroups(showMembers=False):
|
|
|
51515
51531
|
row['JSON'] = json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=False)
|
|
51516
51532
|
csvPF.WriteRowTitles(row)
|
|
51517
51533
|
continue
|
|
51518
|
-
printGettingEntityItemForWhom(Ent.
|
|
51534
|
+
printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
|
|
51519
51535
|
currentCount(i, count)))
|
|
51520
51536
|
pageMessage = getPageMessage()
|
|
51521
51537
|
try:
|
|
@@ -51530,7 +51546,7 @@ def doPrintCourseStudentGroups(showMembers=False):
|
|
|
51530
51546
|
itemCount += len(students)
|
|
51531
51547
|
continue
|
|
51532
51548
|
for member in students:
|
|
51533
|
-
member['userEmail'] =
|
|
51549
|
+
member['userEmail'] = studentIdEmailMap.get(member['userId'], member['userId'])
|
|
51534
51550
|
except GAPI.notFound as e:
|
|
51535
51551
|
entityActionFailedWarning([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
|
|
51536
51552
|
continue
|
|
@@ -51562,8 +51578,29 @@ def doPrintCourseStudentGroups(showMembers=False):
|
|
|
51562
51578
|
# gam sync course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
|
51563
51579
|
# gam clear course-studentgroup-members <CourseID> <StudentGroupID>
|
|
51564
51580
|
def doProcessCourseStudentGroupMembers():
|
|
51565
|
-
def
|
|
51566
|
-
|
|
51581
|
+
def _getCourseStudents():
|
|
51582
|
+
studentIdEmailMap = {}
|
|
51583
|
+
studentEmailIdMap = {}
|
|
51584
|
+
try:
|
|
51585
|
+
students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
|
|
51586
|
+
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
|
51587
|
+
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
|
51588
|
+
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
|
51589
|
+
courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
|
|
51590
|
+
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
|
51591
|
+
for student in students:
|
|
51592
|
+
studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress'].lower()
|
|
51593
|
+
studentEmailIdMap[student['profile']['emailAddress'].lower()] = student['profile']['id']
|
|
51594
|
+
return (studentIdEmailMap, studentEmailIdMap)
|
|
51595
|
+
except GAPI.notFound as e:
|
|
51596
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51597
|
+
except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
|
|
51598
|
+
entityActionFailedExit([Ent.COURSE, courseId], str(e))
|
|
51599
|
+
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51600
|
+
ClientAPIAccessDeniedExit(str(e))
|
|
51601
|
+
|
|
51602
|
+
def _getGroupCurrentStudents():
|
|
51603
|
+
printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId], ''))
|
|
51567
51604
|
pageMessage = getPageMessage()
|
|
51568
51605
|
try:
|
|
51569
51606
|
return callGAPIpages(ocroom.courses().studentGroups().studentGroupMembers(), 'list', 'studentGroupMembers',
|
|
@@ -51581,18 +51618,24 @@ def doProcessCourseStudentGroupMembers():
|
|
|
51581
51618
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51582
51619
|
ClientAPIAccessDeniedExit(str(e))
|
|
51583
51620
|
|
|
51584
|
-
def
|
|
51585
|
-
|
|
51586
|
-
|
|
51587
|
-
|
|
51588
|
-
|
|
51589
|
-
|
|
51590
|
-
|
|
51591
|
-
|
|
51592
|
-
|
|
51593
|
-
|
|
51594
|
-
|
|
51595
|
-
|
|
51621
|
+
def _validateClStudents(clStudents):
|
|
51622
|
+
status = True
|
|
51623
|
+
clStudentIds = []
|
|
51624
|
+
count = len(clStudents)
|
|
51625
|
+
i = 0
|
|
51626
|
+
kvList = [Ent.COURSE, courseId, Ent.STUDENT, '']
|
|
51627
|
+
for student in clStudents:
|
|
51628
|
+
i += 1
|
|
51629
|
+
student = normalizeEmailAddressOrUID(student)
|
|
51630
|
+
if student in studentIdEmailMap:
|
|
51631
|
+
clStudentIds.append(student)
|
|
51632
|
+
elif student in studentEmailIdMap:
|
|
51633
|
+
clStudentIds.append(studentEmailIdMap[student])
|
|
51634
|
+
else:
|
|
51635
|
+
kvList[-1] = student
|
|
51636
|
+
entityActionFailedWarning(kvList, Msg.STUDENT_NOT_IN_COURSE, i, count)
|
|
51637
|
+
status = False
|
|
51638
|
+
return clStudentIds if status else None
|
|
51596
51639
|
|
|
51597
51640
|
def _processStudent(function, kvList, kwargs, i, count):
|
|
51598
51641
|
try:
|
|
@@ -51611,85 +51654,69 @@ def doProcessCourseStudentGroupMembers():
|
|
|
51611
51654
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
|
51612
51655
|
ClientAPIAccessDeniedExit(str(e))
|
|
51613
51656
|
|
|
51614
|
-
def _addStudents(students
|
|
51657
|
+
def _addStudents(students):
|
|
51615
51658
|
count = len(students)
|
|
51616
51659
|
i = 0
|
|
51617
|
-
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.
|
|
51618
|
-
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.
|
|
51660
|
+
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
|
|
51661
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
|
|
51619
51662
|
kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'body': {'userId': ''}}
|
|
51663
|
+
Ind.Increment()
|
|
51620
51664
|
for student in students:
|
|
51621
51665
|
i += 1
|
|
51622
|
-
|
|
51623
|
-
|
|
51624
|
-
if userId is None:
|
|
51625
|
-
continue
|
|
51626
|
-
kvList[-1] = student
|
|
51627
|
-
else:
|
|
51628
|
-
userId = student
|
|
51629
|
-
kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
|
|
51630
|
-
kwargs['body']['userId'] = userId
|
|
51666
|
+
kvList[-1] = studentIdEmailMap[student]
|
|
51667
|
+
kwargs['body']['userId'] = student
|
|
51631
51668
|
_processStudent('create', kvList, kwargs, i, count)
|
|
51669
|
+
Ind.Decrement()
|
|
51632
51670
|
|
|
51633
|
-
def _removeStudents(students
|
|
51671
|
+
def _removeStudents(students):
|
|
51634
51672
|
count = len(students)
|
|
51635
51673
|
i = 0
|
|
51636
|
-
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.
|
|
51637
|
-
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.
|
|
51674
|
+
entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
|
|
51675
|
+
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
|
|
51638
51676
|
kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'userId': ''}
|
|
51677
|
+
Ind.Increment()
|
|
51639
51678
|
for student in students:
|
|
51640
51679
|
i += 1
|
|
51641
|
-
|
|
51642
|
-
|
|
51643
|
-
if userId is None:
|
|
51644
|
-
continue
|
|
51645
|
-
kvList[-1] = student
|
|
51646
|
-
else:
|
|
51647
|
-
userId = student
|
|
51648
|
-
kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
|
|
51649
|
-
kwargs['userId'] = userId
|
|
51680
|
+
kvList[-1] = studentIdEmailMap[student]
|
|
51681
|
+
kwargs['userId'] = student
|
|
51650
51682
|
_processStudent('delete', kvList, kwargs, i, count)
|
|
51683
|
+
Ind.Decrement()
|
|
51651
51684
|
|
|
51652
51685
|
croom = buildGAPIObject(API.CLASSROOM)
|
|
51653
|
-
cd = buildGAPIObject(API.DIRECTORY)
|
|
51654
51686
|
action = Act.Get()
|
|
51655
51687
|
courseId = getString(Cmd.OB_COURSE_ID)
|
|
51656
51688
|
studentGroupId = getString(Cmd.OB_STUDENTGROUP_ID)
|
|
51657
51689
|
if action != Act.CLEAR:
|
|
51658
51690
|
_, clStudents = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, groupMemberType=Ent.TYPE_USER)
|
|
51659
|
-
|
|
51691
|
+
clStudentIds = []
|
|
51660
51692
|
checkForExtraneousArguments()
|
|
51661
51693
|
_, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
|
|
51662
51694
|
if count == 0:
|
|
51663
51695
|
return
|
|
51664
51696
|
ocroom = coursesInfo[courseId]['croom']
|
|
51665
51697
|
courseId = coursesInfo[courseId]['id']
|
|
51698
|
+
studentIdEmailMap, studentEmailIdMap = _getCourseStudents()
|
|
51666
51699
|
if action in {Act.SYNC, Act.CLEAR}:
|
|
51667
|
-
currentStudents = [student['userId'] for student in
|
|
51700
|
+
currentStudents = [student['userId'] for student in _getGroupCurrentStudents()]
|
|
51701
|
+
if action != Act.CLEAR:
|
|
51702
|
+
clStudentIds = _validateClStudents(clStudents)
|
|
51703
|
+
if clStudentIds is None:
|
|
51704
|
+
return
|
|
51668
51705
|
if action == Act.CLEAR:
|
|
51669
|
-
_removeStudents(currentStudents
|
|
51706
|
+
_removeStudents(currentStudents)
|
|
51670
51707
|
elif action == Act.DELETE:
|
|
51671
|
-
_removeStudents(
|
|
51708
|
+
_removeStudents(clStudentIds)
|
|
51672
51709
|
elif action in {Act.ADD, Act.CREATE}:
|
|
51673
|
-
_addStudents(
|
|
51710
|
+
_addStudents(clStudentIds)
|
|
51674
51711
|
else: # elif action == Act.SYNC:
|
|
51675
51712
|
currentMembersSet = set(currentStudents)
|
|
51676
|
-
syncMembersSet = set()
|
|
51677
|
-
count = len(clStudents)
|
|
51678
|
-
i = 0
|
|
51679
|
-
kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
|
|
51680
|
-
for student in clStudents:
|
|
51681
|
-
i += 1
|
|
51682
|
-
kvList[-1] = student
|
|
51683
|
-
userId = _getStudentUserId(kvList, student, i, count)
|
|
51684
|
-
if userId is None:
|
|
51685
|
-
continue
|
|
51686
|
-
syncMembersSet.add(userId)
|
|
51713
|
+
syncMembersSet = set(clStudentIds)
|
|
51687
51714
|
removeStudentsSet = currentMembersSet-syncMembersSet
|
|
51688
51715
|
addStudentsSet = syncMembersSet-currentMembersSet
|
|
51689
51716
|
Act.Set(Act.DELETE)
|
|
51690
|
-
_removeStudents(removeStudentsSet
|
|
51717
|
+
_removeStudents(removeStudentsSet)
|
|
51691
51718
|
Act.Set(Act.ADD)
|
|
51692
|
-
_addStudents(addStudentsSet
|
|
51719
|
+
_addStudents(addStudentsSet)
|
|
51693
51720
|
|
|
51694
51721
|
# gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
|
|
51695
51722
|
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
|
@@ -56227,7 +56254,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
|
|
|
56227
56254
|
count = 0
|
|
56228
56255
|
if revisionsEntity['time'][0] == 'before':
|
|
56229
56256
|
for revision in results:
|
|
56230
|
-
modifiedDateTime
|
|
56257
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56231
56258
|
if modifiedDateTime >= dateTime:
|
|
56232
56259
|
break
|
|
56233
56260
|
revisionIds.append(revision['id'])
|
|
@@ -56237,7 +56264,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
|
|
|
56237
56264
|
return revisionIds
|
|
56238
56265
|
# time: after
|
|
56239
56266
|
for revision in results:
|
|
56240
|
-
modifiedDateTime
|
|
56267
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56241
56268
|
if modifiedDateTime >= dateTime:
|
|
56242
56269
|
revisionIds.append(revision['id'])
|
|
56243
56270
|
count += 1
|
|
@@ -56249,7 +56276,7 @@ def _selectRevisionIds(drive, fileId, origUser, user, i, count, j, jcount, revis
|
|
|
56249
56276
|
endDateTime = revisionsEntity['range'][2]
|
|
56250
56277
|
count = 0
|
|
56251
56278
|
for revision in results:
|
|
56252
|
-
modifiedDateTime
|
|
56279
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56253
56280
|
if modifiedDateTime >= startDateTime:
|
|
56254
56281
|
if modifiedDateTime >= endDateTime:
|
|
56255
56282
|
break
|
|
@@ -56459,7 +56486,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
|
|
|
56459
56486
|
count = 0
|
|
56460
56487
|
if revisionsEntity['time'][0] == 'before':
|
|
56461
56488
|
for revision in results:
|
|
56462
|
-
modifiedDateTime
|
|
56489
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56463
56490
|
if modifiedDateTime >= dateTime:
|
|
56464
56491
|
break
|
|
56465
56492
|
count += 1
|
|
@@ -56470,7 +56497,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
|
|
|
56470
56497
|
return results[:count]
|
|
56471
56498
|
# time: after
|
|
56472
56499
|
for revision in results:
|
|
56473
|
-
modifiedDateTime
|
|
56500
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56474
56501
|
if modifiedDateTime >= dateTime:
|
|
56475
56502
|
break
|
|
56476
56503
|
count += 1
|
|
@@ -56487,7 +56514,7 @@ def _selectRevisionResults(results, fileId, origUser, revisionsEntity, previewDe
|
|
|
56487
56514
|
count = 0
|
|
56488
56515
|
selectedResults = []
|
|
56489
56516
|
for revision in results:
|
|
56490
|
-
modifiedDateTime
|
|
56517
|
+
modifiedDateTime = iso8601.parse_date(revision['modifiedTime'])
|
|
56491
56518
|
if modifiedDateTime >= startDateTime:
|
|
56492
56519
|
if modifiedDateTime >= endDateTime:
|
|
56493
56520
|
break
|
|
@@ -57025,7 +57052,7 @@ class PermissionMatch():
|
|
|
57025
57052
|
break
|
|
57026
57053
|
elif field in {'expirationstart', 'expirationend'}:
|
|
57027
57054
|
if 'expirationTime' in permission:
|
|
57028
|
-
expirationDateTime
|
|
57055
|
+
expirationDateTime = iso8601.parse_date(permission['expirationTime'])
|
|
57029
57056
|
if field == 'expirationstart':
|
|
57030
57057
|
if expirationDateTime < value:
|
|
57031
57058
|
break
|
|
@@ -65073,7 +65100,7 @@ def _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess):
|
|
|
65073
65100
|
# (mappermissionsdomain <DomainName> <DomainName>)*
|
|
65074
65101
|
# [moveToNewOwnersRoot [<Boolean>]]
|
|
65075
65102
|
# [updatesheetprotectedranges [<Boolean>]]
|
|
65076
|
-
# [sendemail] [emailmessage <String>]
|
|
65103
|
+
# [sendemail|sendnotification] [emailmessage <String>]
|
|
65077
65104
|
# [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
|
65078
65105
|
def createDriveFileACL(users, useDomainAdminAccess=False):
|
|
65079
65106
|
moveToNewOwnersRoot = False
|
|
@@ -65117,7 +65144,7 @@ def createDriveFileACL(users, useDomainAdminAccess=False):
|
|
|
65117
65144
|
elif myarg in {'expiration', 'expires'}:
|
|
65118
65145
|
expirationLocation = Cmd.Location()
|
|
65119
65146
|
body['expirationTime'] = getTimeOrDeltaFromNow()
|
|
65120
|
-
elif myarg
|
|
65147
|
+
elif myarg in {'sendemail', 'sendnotification'}:
|
|
65121
65148
|
sendNotificationEmail = True
|
|
65122
65149
|
elif myarg == 'emailmessage':
|
|
65123
65150
|
sendNotificationEmail = True
|
|
@@ -65373,7 +65400,7 @@ def doUpdateDriveFileACLs():
|
|
|
65373
65400
|
updateDriveFileACLs([_getAdminEmail()], True)
|
|
65374
65401
|
|
|
65375
65402
|
# gam [<UserTypeEntity>] create permissions <DriveFileEntity> <DriveFilePermissionsEntity> [asadmin]
|
|
65376
|
-
# [expiration <Time>] [
|
|
65403
|
+
# [expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
|
|
65377
65404
|
# [moveToNewOwnersRoot [<Boolean>]]
|
|
65378
65405
|
# <PermissionMatch>* [<PermissionMatchAction>]
|
|
65379
65406
|
def createDriveFilePermissions(users, useDomainAdminAccess=False):
|
|
@@ -65491,7 +65518,7 @@ def createDriveFilePermissions(users, useDomainAdminAccess=False):
|
|
|
65491
65518
|
moveToNewOwnersRoot = getBoolean()
|
|
65492
65519
|
elif myarg in {'expiration', 'expires'}:
|
|
65493
65520
|
expiration = getTimeOrDeltaFromNow()
|
|
65494
|
-
elif myarg
|
|
65521
|
+
elif myarg in {'sendemail', 'sendnotification'}:
|
|
65495
65522
|
sendNotificationEmail = True
|
|
65496
65523
|
elif myarg == 'emailmessage':
|
|
65497
65524
|
sendNotificationEmail = True
|
|
@@ -148,13 +148,12 @@ def parse_date(datestring):
|
|
|
148
148
|
groups = m.groupdict()
|
|
149
149
|
tz = parse_timezone(groups)
|
|
150
150
|
try:
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
tz)
|
|
151
|
+
return datetime(year=int(groups['year']),
|
|
152
|
+
month=int(groups['month']),
|
|
153
|
+
day=int(groups['day']),
|
|
154
|
+
hour=int(groups['hour']),
|
|
155
|
+
minute=int(groups['minute']),
|
|
156
|
+
second=int(groups['second']),
|
|
157
|
+
tzinfo=tz)
|
|
159
158
|
except Exception as e:
|
|
160
159
|
raise ParseError(e)
|
gam/gamlib/glmsgs.py
CHANGED
|
@@ -499,6 +499,7 @@ STATISTICS_MOVE_FILE = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut e
|
|
|
499
499
|
STATISTICS_MOVE_FOLDER = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Move Failed: {6}, Not writable: {7}'
|
|
500
500
|
STATISTICS_USER_NOT_ORGANIZER = 'User not organizer: {0}'
|
|
501
501
|
STRING_LENGTH = 'string length'
|
|
502
|
+
STUDENT_NOT_IN_COURSE = 'Student not in course'
|
|
502
503
|
SUBKEY_FIELD_MISMATCH = 'subkeyfield {0} does not match saved subkeyfield {1}'
|
|
503
504
|
SUBSCRIPTION_NOT_FOUND = 'Could not find subscription'
|
|
504
505
|
SUFFIX_NOT_ALLOWED_WITH_CUSTOMLANGUAGE = 'Suffix {0} not allowed with customLanguage {1}'
|
gam/gamlib/glskus.py
CHANGED
|
@@ -100,7 +100,7 @@ _SKUS = {
|
|
|
100
100
|
'1010470003': {
|
|
101
101
|
'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
|
|
102
102
|
'1010470004': {
|
|
103
|
-
'product': '101047', 'aliases': ['geminiedu'], 'displayName': '
|
|
103
|
+
'product': '101047', 'aliases': ['gaiproedu', 'geminiedu'], 'displayName': 'Google AI Pro for Education'},
|
|
104
104
|
'1010470005': {
|
|
105
105
|
'product': '101047', 'aliases': ['geminiedupremium'], 'displayName': 'Gemini Education Premium'},
|
|
106
106
|
'1010470006': {
|