mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-03 19:23:44 +00:00
Added commands to manage classroom/course announcements.
This commit is contained in:
@ -3120,8 +3120,15 @@ gam delete courses <CourseEntity> [archive|archived]
|
|||||||
gam course <CourseID> create|add alias <CourseAlias>
|
gam course <CourseID> create|add alias <CourseAlias>
|
||||||
gam course <CourseID> delete alias <CourseAlias>
|
gam course <CourseID> delete alias <CourseAlias>
|
||||||
|
|
||||||
|
gam course <CourseID> create announcement
|
||||||
|
text <String> [scheduledtime <Time>] [state draft|published]
|
||||||
|
gam course <CourseID> remove announcement <CourseAnnouncementID>
|
||||||
|
gam course <CourseID> update announcement <CourseAnnouncementID>
|
||||||
|
[text <String>] [scheduledtime <Time>] [state published]
|
||||||
|
|
||||||
gam course <CourseID> create|add topic <CourseTopic>
|
gam course <CourseID> create|add topic <CourseTopic>
|
||||||
gam course <CourseID> delete topic <CourseTopicID>
|
gam course <CourseID> delete topic <CourseTopicID>
|
||||||
|
gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
|
||||||
|
|
||||||
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>
|
||||||
@ -3133,8 +3140,15 @@ gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
|
|||||||
gam courses <CourseEntity> create|add alias <CourseAliasEntity>
|
gam courses <CourseEntity> create|add alias <CourseAliasEntity>
|
||||||
gam courses <CourseEntity> delete alias <CourseAliasEntity>
|
gam courses <CourseEntity> delete alias <CourseAliasEntity>
|
||||||
|
|
||||||
|
gam courses <CourseEntity> create announcement
|
||||||
|
text <String> [scheduledtime <Time>] [state draft|published]
|
||||||
|
gam courses <CourseEntity> remove announcement <CourseAnnouncementIDEntity>
|
||||||
|
gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
|
||||||
|
[text <String>] [scheduledtime <Time>] [state published]
|
||||||
|
|
||||||
gam courses <CourseEntity> create|add topic <CourseTopicEntity>
|
gam courses <CourseEntity> create|add topic <CourseTopicEntity>
|
||||||
gam courses <CourseEntity> delete topic <CourseTopicIDEntity>
|
gam courses <CourseEntity> delete topic <CourseTopicIDEntity>
|
||||||
|
gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
|
||||||
|
|
||||||
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>
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
|
7.11.00
|
||||||
|
|
||||||
|
Added commands to manage classroom/course announcements.
|
||||||
|
|
||||||
|
* See: https://github.com/GAM-team/GAM/wiki/Classroom-Courses#manage-course-announcements
|
||||||
|
|
||||||
|
Upgraded to OpenSSL 3.5.1.
|
||||||
|
|
||||||
7.10.10
|
7.10.10
|
||||||
|
|
||||||
Added choices `text` and `hyperlink` to option `showwebviewlink` in `gam [<UserTypeEntity>] print|show shareddrives`.
|
Added choices `text` and `hyperlink` to option `showwebviewlink` in `gam [<UserTypeEntity>] print|show shareddrives`.
|
||||||
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
||||||
* `showwebviewlink hyperlink` - Dsiplays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveNamw>")
|
* `showwebviewlink hyperlink` - Displays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveName>")`
|
||||||
|
|
||||||
7.10.09
|
7.10.09
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||||
__version__ = '7.10.10'
|
__version__ = '7.11.00'
|
||||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||||
|
|
||||||
#pylint: disable=wrong-import-position
|
#pylint: disable=wrong-import-position
|
||||||
@ -46776,6 +46776,13 @@ COURSE_STATE_MAPS = {
|
|||||||
'published': 'PUBLISHED',
|
'published': 'PUBLISHED',
|
||||||
'deleted': 'DELETED',
|
'deleted': 'DELETED',
|
||||||
},
|
},
|
||||||
|
Cmd.OB_COURSE_ANNOUNCEMENT_ADD_STATE_LIST: {
|
||||||
|
'draft': 'DRAFT',
|
||||||
|
'published': 'PUBLISHED',
|
||||||
|
},
|
||||||
|
Cmd.OB_COURSE_ANNOUNCEMENT_UPDATE_STATE_LIST: {
|
||||||
|
'published': 'PUBLISHED',
|
||||||
|
},
|
||||||
Cmd.OB_COURSE_WORK_STATE_LIST: {
|
Cmd.OB_COURSE_WORK_STATE_LIST: {
|
||||||
'draft': 'DRAFT',
|
'draft': 'DRAFT',
|
||||||
'published': 'PUBLISHED',
|
'published': 'PUBLISHED',
|
||||||
@ -48923,7 +48930,7 @@ def doPrintCourseParticipants():
|
|||||||
csvPF.SetSortTitles(COURSE_PARTICIPANTS_SORT_TITLES)
|
csvPF.SetSortTitles(COURSE_PARTICIPANTS_SORT_TITLES)
|
||||||
csvPF.writeCSVfile('Course Participants')
|
csvPF.writeCSVfile('Course Participants')
|
||||||
|
|
||||||
def _batchAddItemsToCourse(croom, courseId, i, count, addParticipants, role):
|
def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
|
||||||
_ADD_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
|
_ADD_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
|
||||||
GAPI.ALREADY_EXISTS: Msg.DUPLICATE,
|
GAPI.ALREADY_EXISTS: Msg.DUPLICATE,
|
||||||
GAPI.FAILED_PRECONDITION: Msg.NOT_ALLOWED}
|
GAPI.FAILED_PRECONDITION: Msg.NOT_ALLOWED}
|
||||||
@ -48939,7 +48946,7 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addParticipants, role):
|
|||||||
else:
|
else:
|
||||||
errMsg = getHTTPError(_ADD_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
|
errMsg = getHTTPError(_ADD_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
|
||||||
if (reason == GAPI.PERMISSION_DENIED) and (ri[RI_ROLE] in {Ent.STUDENT, Ent.TEACHER}) and ('CannotDirectAddUser' in errMsg):
|
if (reason == GAPI.PERMISSION_DENIED) and (ri[RI_ROLE] in {Ent.STUDENT, Ent.TEACHER}) and ('CannotDirectAddUser' in errMsg):
|
||||||
errMsg += f' Add external user with: gam user {ri[RI_ITEM]} create classroominvitation courses {ri[RI_ENTITY]} role {Ent.Singular(ri[RI_ROLE])}'
|
errMsg += f' Add external user with: gam user {ri[RI_ITEM]} create classroominvitation courses {ri[RI_ENTITY]} addType {Ent.Singular(ri[RI_ROLE])}'
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
return
|
return
|
||||||
waitOnFailure(1, 10, reason, message)
|
waitOnFailure(1, 10, reason, message)
|
||||||
@ -48961,39 +48968,44 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addParticipants, role):
|
|||||||
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable) as e:
|
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable) as e:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
|
|
||||||
if role == Ent.STUDENT:
|
if addType == Ent.STUDENT:
|
||||||
service = croom.courses().students()
|
service = croom.courses().students()
|
||||||
attribute = 'userId'
|
attribute = 'userId'
|
||||||
elif role == Ent.TEACHER:
|
elif addType == Ent.TEACHER:
|
||||||
service = croom.courses().teachers()
|
service = croom.courses().teachers()
|
||||||
attribute = 'userId'
|
attribute = 'userId'
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif addType == Ent.COURSE_ALIAS:
|
||||||
service = croom.courses().aliases()
|
service = croom.courses().aliases()
|
||||||
attribute = 'alias'
|
attribute = 'alias'
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
service = croom.courses().topics()
|
service = croom.courses().topics()
|
||||||
attribute = 'name'
|
attribute = 'name'
|
||||||
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
service = croom.courses().announcements()
|
||||||
|
attribute = 'text'
|
||||||
method = getattr(service, 'create')
|
method = getattr(service, 'create')
|
||||||
Act.Set(Act.ADD)
|
Act.Set(Act.ADD)
|
||||||
jcount = len(addParticipants)
|
jcount = len(addItems)
|
||||||
noScopeCourseId = removeCourseIdScope(courseId)
|
noScopeCourseId = removeCourseIdScope(courseId)
|
||||||
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, role, i, count)
|
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, addType, i, count)
|
||||||
Ind.Increment()
|
Ind.Increment()
|
||||||
svcargs = dict([('courseId', courseId), ('body', {attribute: None}), ('fields', '')]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
svcargs = dict([('courseId', courseId), ('body', {attribute: None}), ('fields', '')]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
||||||
dbatch = croom.new_batch_http_request(callback=_callbackAddItemsToCourse)
|
dbatch = croom.new_batch_http_request(callback=_callbackAddItemsToCourse)
|
||||||
bcount = 0
|
bcount = 0
|
||||||
j = 0
|
j = 0
|
||||||
for participant in addParticipants:
|
for addItem in addItems:
|
||||||
j += 1
|
j += 1
|
||||||
svcparms = svcargs.copy()
|
svcparms = svcargs.copy()
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if addType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
svcparms['body'][attribute] = cleanItem = normalizeEmailAddressOrUID(participant)
|
svcparms['body'][attribute] = cleanItem = normalizeEmailAddressOrUID(addItem)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif addType == Ent.COURSE_ALIAS:
|
||||||
svcparms['body'][attribute] = addCourseAliasScope(participant)
|
svcparms['body'][attribute] = addCourseAliasScope(addItem)
|
||||||
cleanItem = removeCourseAliasScope(svcparms['body'][attribute])
|
cleanItem = removeCourseAliasScope(svcparms['body'][attribute])
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
svcparms['body'][attribute] = cleanItem = participant
|
svcparms['body'][attribute] = cleanItem = addItem
|
||||||
dbatch.add(method(**svcparms), request_id=batchRequestID(noScopeCourseId, 0, 0, j, jcount, cleanItem, role))
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
svcparms['body'] = cleanItem = addItem
|
||||||
|
dbatch.add(method(**svcparms), request_id=batchRequestID(noScopeCourseId, 0, 0, j, jcount, cleanItem, addType))
|
||||||
bcount += 1
|
bcount += 1
|
||||||
if bcount >= GC.Values[GC.BATCH_SIZE]:
|
if bcount >= GC.Values[GC.BATCH_SIZE]:
|
||||||
executeBatch(dbatch)
|
executeBatch(dbatch)
|
||||||
@ -49003,7 +49015,7 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addParticipants, role):
|
|||||||
dbatch.execute()
|
dbatch.execute()
|
||||||
Ind.Decrement()
|
Ind.Decrement()
|
||||||
|
|
||||||
def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, role):
|
def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeItems, removeType):
|
||||||
_REMOVE_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
|
_REMOVE_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
|
||||||
GAPI.FORBIDDEN: Msg.FORBIDDEN,
|
GAPI.FORBIDDEN: Msg.FORBIDDEN,
|
||||||
GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
|
GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
|
||||||
@ -49024,7 +49036,7 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, r
|
|||||||
try:
|
try:
|
||||||
callGAPI(service, 'delete',
|
callGAPI(service, 'delete',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED,
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED,
|
||||||
GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
|
GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE, GAPI.FAILED_PRECONDITION],
|
||||||
retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE], triesLimit=0 if reason != GAPI.NOT_FOUND else 3,
|
retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE], triesLimit=0 if reason != GAPI.NOT_FOUND else 3,
|
||||||
courseId=addCourseIdScope(ri[RI_ENTITY]),
|
courseId=addCourseIdScope(ri[RI_ENTITY]),
|
||||||
body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
|
body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
|
||||||
@ -49035,42 +49047,47 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, r
|
|||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.FORBIDDEN, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.FORBIDDEN, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except GAPI.permissionDenied:
|
except GAPI.permissionDenied:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.PERMISSION_DENIED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.PERMISSION_DENIED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable) as e:
|
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable, GAPI.failedPrecondition) as e:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
|
|
||||||
if role == Ent.STUDENT:
|
if removeType == Ent.STUDENT:
|
||||||
service = croom.courses().students()
|
service = croom.courses().students()
|
||||||
attribute = 'userId'
|
attribute = 'userId'
|
||||||
elif role == Ent.TEACHER:
|
elif removeType == Ent.TEACHER:
|
||||||
service = croom.courses().teachers()
|
service = croom.courses().teachers()
|
||||||
attribute = 'userId'
|
attribute = 'userId'
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif removeType == Ent.COURSE_ALIAS:
|
||||||
service = croom.courses().aliases()
|
service = croom.courses().aliases()
|
||||||
attribute = 'alias'
|
attribute = 'alias'
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif removeType == Ent.COURSE_TOPIC:
|
||||||
service = croom.courses().topics()
|
service = croom.courses().topics()
|
||||||
attribute = 'id'
|
attribute = 'id'
|
||||||
|
else: # removeType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
service = croom.courses().announcements()
|
||||||
|
attribute = 'id'
|
||||||
method = getattr(service, 'delete')
|
method = getattr(service, 'delete')
|
||||||
Act.Set(Act.REMOVE)
|
Act.Set(Act.REMOVE)
|
||||||
jcount = len(removeParticipants)
|
jcount = len(removeItems)
|
||||||
noScopeCourseId = removeCourseIdScope(courseId)
|
noScopeCourseId = removeCourseIdScope(courseId)
|
||||||
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, role, i, count)
|
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, removeType, i, count)
|
||||||
Ind.Increment()
|
Ind.Increment()
|
||||||
svcargs = dict([('courseId', courseId), ('fields', ''), (attribute, None)]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
svcargs = dict([('courseId', courseId), ('fields', ''), (attribute, None)]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
||||||
dbatch = croom.new_batch_http_request(callback=_callbackRemoveItemsFromCourse)
|
dbatch = croom.new_batch_http_request(callback=_callbackRemoveItemsFromCourse)
|
||||||
bcount = 0
|
bcount = 0
|
||||||
j = 0
|
j = 0
|
||||||
for participant in removeParticipants:
|
for removeItem in removeItems:
|
||||||
j += 1
|
j += 1
|
||||||
svcparms = svcargs.copy()
|
svcparms = svcargs.copy()
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if removeType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
svcparms[attribute] = cleanItem = normalizeEmailAddressOrUID(participant)
|
svcparms[attribute] = cleanItem = normalizeEmailAddressOrUID(removeItem)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif removeType == Ent.COURSE_ALIAS:
|
||||||
svcparms[attribute] = addCourseAliasScope(participant)
|
svcparms[attribute] = addCourseAliasScope(removeItem)
|
||||||
cleanItem = removeCourseAliasScope(svcparms[attribute])
|
cleanItem = removeCourseAliasScope(svcparms[attribute])
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif removeType == Ent.COURSE_TOPIC:
|
||||||
svcparms[attribute] = cleanItem = participant
|
svcparms[attribute] = cleanItem = removeItem
|
||||||
dbatch.add(method(**svcparms), request_id=batchRequestID(noScopeCourseId, 0, 0, j, jcount, cleanItem, role))
|
else: # removeType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
svcparms[attribute] = cleanItem = removeItem
|
||||||
|
dbatch.add(method(**svcparms), request_id=batchRequestID(noScopeCourseId, 0, 0, j, jcount, cleanItem, removeType))
|
||||||
bcount += 1
|
bcount += 1
|
||||||
if bcount >= GC.Values[GC.BATCH_SIZE]:
|
if bcount >= GC.Values[GC.BATCH_SIZE]:
|
||||||
executeBatch(dbatch)
|
executeBatch(dbatch)
|
||||||
@ -49100,9 +49117,28 @@ def _updateCourseOwner(croom, courseId, owner, i, count):
|
|||||||
entityActionPerformedMessage([Ent.COURSE, removeCourseIdScope(courseId), Ent.TEACHER, owner], Msg.ALREADY_WAS_OWNER, i, count)
|
entityActionPerformedMessage([Ent.COURSE, removeCourseIdScope(courseId), Ent.TEACHER, owner], Msg.ALREADY_WAS_OWNER, i, count)
|
||||||
Act.Set(action)
|
Act.Set(action)
|
||||||
|
|
||||||
ADD_REMOVE_PARTICIPANT_TYPES_MAP = {
|
def getCourseAnnouncement(createCmd):
|
||||||
|
body = {}
|
||||||
|
while Cmd.ArgumentsRemaining():
|
||||||
|
myarg = getArgument()
|
||||||
|
if myarg == 'text':
|
||||||
|
body['text'] = getString(Cmd.OB_STRING, minLen=1, maxLen=30000)
|
||||||
|
elif myarg == 'scheduledtime':
|
||||||
|
body['scheduledTime'] = getTimeOrDeltaFromNow()
|
||||||
|
elif myarg == 'state':
|
||||||
|
body['state'] = getChoice(COURSE_STATE_MAPS[Cmd.OB_COURSE_ANNOUNCEMENT_ADD_STATE_LIST if createCmd else Cmd.OB_COURSE_ANNOUNCEMENT_UPDATE_STATE_LIST],
|
||||||
|
mapChoice=True)
|
||||||
|
else:
|
||||||
|
unknownArgumentExit()
|
||||||
|
if createCmd and 'text' not in body:
|
||||||
|
missingArgumentExit('text <String>')
|
||||||
|
return body
|
||||||
|
|
||||||
|
ADD_REMOVE_UPDATE_ITEM_TYPES_MAP = {
|
||||||
'alias': Ent.COURSE_ALIAS,
|
'alias': Ent.COURSE_ALIAS,
|
||||||
'aliases': Ent.COURSE_ALIAS,
|
'aliases': Ent.COURSE_ALIAS,
|
||||||
|
'announcement': Ent.COURSE_ANNOUNCEMENT,
|
||||||
|
'announcements': Ent.COURSE_ANNOUNCEMENT,
|
||||||
'student': Ent.STUDENT,
|
'student': Ent.STUDENT,
|
||||||
'students': Ent.STUDENT,
|
'students': Ent.STUDENT,
|
||||||
'teacher': Ent.TEACHER,
|
'teacher': Ent.TEACHER,
|
||||||
@ -49123,6 +49159,10 @@ PARTICIPANT_EN_MAP = {
|
|||||||
|
|
||||||
# gam courses <CourseEntity> create alias <CourseAliasEntity>
|
# gam courses <CourseEntity> create alias <CourseAliasEntity>
|
||||||
# gam course <CourseID> create alias <CourseAlias>
|
# gam course <CourseID> create alias <CourseAlias>
|
||||||
|
# gam courses <CourseEntity> create announcement
|
||||||
|
# text <String> [scheduledtime <Time>] [state draft|published]
|
||||||
|
# gam course <CourseID> create announcement
|
||||||
|
# text <String> [scheduledtime <Time>] [state draft|published]
|
||||||
# gam courses <CourseEntity> create topic <CourseTopicEntity>
|
# gam courses <CourseEntity> create topic <CourseTopicEntity>
|
||||||
# gam course <CourseID> create topic <CourseTopic>
|
# gam course <CourseID> create topic <CourseTopic>
|
||||||
# gam courses <CourseEntity> create students <UserTypeEntity>
|
# gam courses <CourseEntity> create students <UserTypeEntity>
|
||||||
@ -49131,35 +49171,39 @@ PARTICIPANT_EN_MAP = {
|
|||||||
# gam course <CourseID> create teacher [makefirstteacherowner] <EmailAddress>
|
# gam course <CourseID> create teacher [makefirstteacherowner] <EmailAddress>
|
||||||
def doCourseAddItems(courseIdList, getEntityListArg):
|
def doCourseAddItems(courseIdList, getEntityListArg):
|
||||||
croom = buildGAPIObject(API.CLASSROOM)
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
role = getChoice(ADD_REMOVE_PARTICIPANT_TYPES_MAP, mapChoice=True)
|
addType = getChoice(ADD_REMOVE_UPDATE_ITEM_TYPES_MAP, mapChoice=True)
|
||||||
if role == Ent.TEACHER:
|
if addType == Ent.TEACHER:
|
||||||
makeFirstTeacherOwner = checkArgumentPresent(['makefirstteacherowner'])
|
makeFirstTeacherOwner = checkArgumentPresent(['makefirstteacherowner'])
|
||||||
else:
|
else:
|
||||||
makeFirstTeacherOwner = False
|
makeFirstTeacherOwner = False
|
||||||
if not getEntityListArg:
|
if not getEntityListArg:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if addType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
addItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
addItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif addType == Ent.COURSE_ALIAS:
|
||||||
addItems = getStringReturnInList(Cmd.OB_COURSE_ALIAS)
|
addItems = getStringReturnInList(Cmd.OB_COURSE_ALIAS)
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
addItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC)
|
addItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC)
|
||||||
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
addItems = [getCourseAnnouncement(True)]
|
||||||
courseParticipantLists = None
|
courseParticipantLists = None
|
||||||
else:
|
else:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if addType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
_, addItems = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS,
|
_, addItems = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS,
|
||||||
typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[role]},
|
typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[addType]},
|
||||||
isSuspended=False, isArchived=False)
|
isSuspended=False, isArchived=False)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif addType == Ent.COURSE_ALIAS:
|
||||||
addItems = getEntityList(Cmd.OB_COURSE_ALIAS_ENTITY, shlexSplit=True)
|
addItems = getEntityList(Cmd.OB_COURSE_ALIAS_ENTITY, shlexSplit=True)
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
addItems = getEntityList(Cmd.OB_COURSE_TOPIC_ENTITY, shlexSplit=True)
|
addItems = getEntityList(Cmd.OB_COURSE_TOPIC_ENTITY, shlexSplit=True)
|
||||||
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
addItems = getCourseAnnouncement(True)
|
||||||
courseParticipantLists = addItems if isinstance(addItems, dict) else None
|
courseParticipantLists = addItems if isinstance(addItems, dict) else None
|
||||||
if courseParticipantLists is None:
|
if courseParticipantLists is None:
|
||||||
firstTeacher = None
|
firstTeacher = None
|
||||||
if makeFirstTeacherOwner and addItems:
|
if makeFirstTeacherOwner and addItems:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, role == Ent.COURSE_TOPIC,
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, addType in {Ent.COURSE_TOPIC, Ent.COURSE_ANNOUNCEMENT},
|
||||||
addCIIdScope=courseParticipantLists is None)
|
addCIIdScope=courseParticipantLists is None)
|
||||||
for courseId, courseInfo in coursesInfo.items():
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
i += 1
|
i += 1
|
||||||
@ -49169,43 +49213,51 @@ def doCourseAddItems(courseIdList, getEntityListArg):
|
|||||||
if makeFirstTeacherOwner and addItems:
|
if makeFirstTeacherOwner and addItems:
|
||||||
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
firstTeacher = normalizeEmailAddressOrUID(addItems[0])
|
||||||
courseId = addCourseIdScope(courseId)
|
courseId = addCourseIdScope(courseId)
|
||||||
_batchAddItemsToCourse(courseInfo['croom'], courseId, i, count, addItems, role)
|
_batchAddItemsToCourse(courseInfo['croom'], courseId, i, count, addItems, addType)
|
||||||
if makeFirstTeacherOwner and firstTeacher:
|
if makeFirstTeacherOwner and firstTeacher:
|
||||||
_updateCourseOwner(courseInfo['croom'], courseId, firstTeacher, i, count)
|
_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>
|
||||||
|
# gam courses <CourseEntity> remove announcement <CourseAnnouncementIDEntity>
|
||||||
|
# gam course <CourseID> remove announcement <CourseAnnouncementID>
|
||||||
# gam courses <CourseEntity> remove topic <CourseTopicIDEntity>
|
# gam courses <CourseEntity> remove topic <CourseTopicIDEntity>
|
||||||
# gam course <CourseID> remove topic <CourseTopicID>
|
# gam course <CourseID> remove topic <CourseTopicID>
|
||||||
# gam courses <CourseEntity> remove teachers|students [owneracccess] <UserTypeEntity>
|
# gam courses <CourseEntity> remove teachers|students [owneracccess] <UserTypeEntity>
|
||||||
# gam course <CourseID> remove teacher|student [owneracccess] <EmailAddress>
|
# gam course <CourseID> remove teacher|student [owneracccess] <EmailAddress>
|
||||||
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)
|
removeType = getChoice(ADD_REMOVE_UPDATE_ITEM_TYPES_MAP, mapChoice=True)
|
||||||
if not getEntityListArg:
|
if not getEntityListArg:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if removeType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS]
|
||||||
if checkArgumentPresent(OWNER_ACCESS_OPTIONS):
|
if checkArgumentPresent(OWNER_ACCESS_OPTIONS):
|
||||||
useOwnerAccess = True
|
useOwnerAccess = True
|
||||||
removeItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
removeItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS)
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif removeType == Ent.COURSE_ALIAS:
|
||||||
useOwnerAccess = False
|
useOwnerAccess = False
|
||||||
removeItems = getStringReturnInList(Cmd.OB_COURSE_ALIAS)
|
removeItems = getStringReturnInList(Cmd.OB_COURSE_ALIAS)
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif removeType == Ent.COURSE_TOPIC:
|
||||||
useOwnerAccess = True
|
useOwnerAccess = True
|
||||||
removeItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC_ID)
|
removeItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC_ID)
|
||||||
|
else: # removeType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
useOwnerAccess = True
|
||||||
|
removeItems = getStringReturnInList(Cmd.OB_COURSE_ANNOUNCEMENT_ID)
|
||||||
courseParticipantLists = None
|
courseParticipantLists = None
|
||||||
else:
|
else:
|
||||||
if role in {Ent.STUDENT, Ent.TEACHER}:
|
if removeType in {Ent.STUDENT, Ent.TEACHER}:
|
||||||
useOwnerAccess = checkArgumentPresent(OWNER_ACCESS_OPTIONS)
|
useOwnerAccess = checkArgumentPresent(OWNER_ACCESS_OPTIONS)
|
||||||
_, removeItems = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS,
|
_, removeItems = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS,
|
||||||
typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[role]})
|
typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[removeType]})
|
||||||
elif role == Ent.COURSE_ALIAS:
|
elif removeType == Ent.COURSE_ALIAS:
|
||||||
useOwnerAccess = False
|
useOwnerAccess = False
|
||||||
removeItems = getEntityList(Cmd.OB_COURSE_ALIAS_ENTITY, shlexSplit=True)
|
removeItems = getEntityList(Cmd.OB_COURSE_ALIAS_ENTITY, shlexSplit=True)
|
||||||
else: # role == Ent.COURSE_TOPIC:
|
elif removeType == Ent.COURSE_TOPIC:
|
||||||
useOwnerAccess = True
|
useOwnerAccess = True
|
||||||
removeItems = getEntityList(Cmd.OB_COURSE_TOPIC_ID_ENTITY, shlexSplit=True)
|
removeItems = getEntityList(Cmd.OB_COURSE_TOPIC_ID_ENTITY, shlexSplit=True)
|
||||||
|
else: # removeType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
useOwnerAccess = True
|
||||||
|
removeItems = getEntityList(Cmd.OB_COURSE_ANNOUNCEMENT_ID_ENTITY, shlexSplit=True)
|
||||||
courseParticipantLists = removeItems if isinstance(removeItems, dict) else None
|
courseParticipantLists = removeItems if isinstance(removeItems, dict) else None
|
||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, useOwnerAccess,
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, useOwnerAccess,
|
||||||
@ -49215,7 +49267,72 @@ def doCourseRemoveItems(courseIdList, getEntityListArg):
|
|||||||
if courseParticipantLists:
|
if courseParticipantLists:
|
||||||
removeItems = courseParticipantLists[courseId]
|
removeItems = courseParticipantLists[courseId]
|
||||||
courseId = addCourseIdScope(courseId)
|
courseId = addCourseIdScope(courseId)
|
||||||
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, role)
|
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, removeType)
|
||||||
|
|
||||||
|
# gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
|
||||||
|
# [text <String>] [scheduledtime <Time>] [state published]
|
||||||
|
# gam course <CourseID> update announcement <CourseAnnouncementID>
|
||||||
|
# [text <String>] [scheduledtime <Time>] [state published]
|
||||||
|
# gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
|
||||||
|
# gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
|
||||||
|
def doCourseUpdateItems(courseIdList, getEntityListArg):
|
||||||
|
croom = buildGAPIObject(API.CLASSROOM)
|
||||||
|
updateType = getChoice(ADD_REMOVE_UPDATE_ITEM_TYPES_MAP, mapChoice=True)
|
||||||
|
if not getEntityListArg:
|
||||||
|
if updateType == Ent.COURSE_TOPIC:
|
||||||
|
useOwnerAccess = True
|
||||||
|
updateItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC_ID)
|
||||||
|
body = {'name': getString(Cmd.OB_COURSE_TOPIC)}
|
||||||
|
else: # updateType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
useOwnerAccess = True
|
||||||
|
updateItems = getStringReturnInList(Cmd.OB_COURSE_ANNOUNCEMENT_ID)
|
||||||
|
body = getCourseAnnouncement(False)
|
||||||
|
courseItemLists = None
|
||||||
|
else:
|
||||||
|
if updateType == Ent.COURSE_TOPIC:
|
||||||
|
useOwnerAccess = True
|
||||||
|
updateItems = getEntityList(Cmd.OB_COURSE_TOPIC_ID_ENTITY, shlexSplit=True)
|
||||||
|
body = {'name': getString(Cmd.OB_COURSE_TOPIC)}
|
||||||
|
else: # updateType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
useOwnerAccess = True
|
||||||
|
updateItems = getEntityList(Cmd.OB_COURSE_ANNOUNCEMENT_ID_ENTITY, shlexSplit=True)
|
||||||
|
body = getCourseAnnouncement(False)
|
||||||
|
courseItemLists = updateItems if isinstance(updateItems, dict) else None
|
||||||
|
checkForExtraneousArguments()
|
||||||
|
i, count, coursesInfo = _getCoursesOwnerInfo(croom, courseIdList, useOwnerAccess,
|
||||||
|
addCIIdScope=courseItemLists is None)
|
||||||
|
for courseId, courseInfo in coursesInfo.items():
|
||||||
|
i += 1
|
||||||
|
if courseItemLists:
|
||||||
|
updateItems = courseItemLists[courseId]
|
||||||
|
courseId = addCourseIdScope(courseId)
|
||||||
|
jcount = len(updateItems)
|
||||||
|
noScopeCourseId = removeCourseIdScope(courseId)
|
||||||
|
if updateType == Ent.COURSE_TOPIC:
|
||||||
|
service = courseInfo['croom'].courses().topics()
|
||||||
|
else: # updateType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
service = courseInfo['croom'].courses().announcements()
|
||||||
|
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, updateType, i, count)
|
||||||
|
Ind.Increment()
|
||||||
|
j = 0
|
||||||
|
for updateItem in updateItems:
|
||||||
|
j += 1
|
||||||
|
try:
|
||||||
|
callGAPI(service, 'patch',
|
||||||
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED,
|
||||||
|
GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
|
retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
|
courseId=addCourseIdScope(courseId), id=updateItem, updateMask=','.join(body.keys()), body=body, fields='')
|
||||||
|
entityActionPerformed([Ent.COURSE, courseId, updateType, updateItem], j, jcount)
|
||||||
|
except GAPI.notFound:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseId, updateType, updateItem], Msg.DOES_NOT_EXIST, j, jcount)
|
||||||
|
except GAPI.forbidden:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseId, updateType, updateItem], Msg.FORBIDDEN, j, jcount)
|
||||||
|
except GAPI.permissionDenied:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseId, updateType, updateItem], Msg.PERMISSION_DENIED, j, jcount)
|
||||||
|
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable) as e:
|
||||||
|
entityActionFailedWarning([Ent.COURSE, courseId, updateType, updateItem], str(e), j, jcount)
|
||||||
|
Ind.Decrement()
|
||||||
|
|
||||||
# gam courses <CourseEntity> clear teachers|students
|
# gam courses <CourseEntity> clear teachers|students
|
||||||
# gam course <CourseID> clear teacher|student
|
# gam course <CourseID> clear teacher|student
|
||||||
@ -77165,6 +77282,7 @@ COURSE_SUBCOMMANDS = {
|
|||||||
'add': (Act.ADD, doCourseAddItems),
|
'add': (Act.ADD, doCourseAddItems),
|
||||||
'clear': (Act.REMOVE, doCourseClearParticipants),
|
'clear': (Act.REMOVE, doCourseClearParticipants),
|
||||||
'remove': (Act.REMOVE, doCourseRemoveItems),
|
'remove': (Act.REMOVE, doCourseRemoveItems),
|
||||||
|
'update': (Act.UPDATE, doCourseUpdateItems),
|
||||||
'sync': (Act.SYNC, doCourseSyncParticipants),
|
'sync': (Act.SYNC, doCourseSyncParticipants),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,8 +875,11 @@ class GamCLArgs():
|
|||||||
OB_CONTACT_GROUP_ITEM = 'ContactGroupItem'
|
OB_CONTACT_GROUP_ITEM = 'ContactGroupItem'
|
||||||
OB_COURSE_ALIAS = 'CourseAlias'
|
OB_COURSE_ALIAS = 'CourseAlias'
|
||||||
OB_COURSE_ALIAS_ENTITY = 'CourseAliasEntity'
|
OB_COURSE_ALIAS_ENTITY = 'CourseAliasEntity'
|
||||||
|
OB_COURSE_ANNOUNCEMENT_ID = "CourseAnnouncementID"
|
||||||
OB_COURSE_ANNOUNCEMENT_ID_ENTITY = "CourseAnnouncementIDEntity"
|
OB_COURSE_ANNOUNCEMENT_ID_ENTITY = "CourseAnnouncementIDEntity"
|
||||||
OB_COURSE_ANNOUNCEMENT_STATE_LIST = "CourseAnnouncementStateList"
|
OB_COURSE_ANNOUNCEMENT_STATE_LIST = "CourseAnnouncementStateList"
|
||||||
|
OB_COURSE_ANNOUNCEMENT_ADD_STATE_LIST = "CourseAnnouncementAddStateList"
|
||||||
|
OB_COURSE_ANNOUNCEMENT_UPDATE_STATE_LIST = "CourseAnnouncementUpdateStateList"
|
||||||
OB_COURSE_ENTITY = 'CourseEntity'
|
OB_COURSE_ENTITY = 'CourseEntity'
|
||||||
OB_COURSE_ID = 'CourseID'
|
OB_COURSE_ID = 'CourseID'
|
||||||
OB_COURSE_MATERIAL_ID_ENTITY = 'CourseMaterialIDEntity'
|
OB_COURSE_MATERIAL_ID_ENTITY = 'CourseMaterialIDEntity'
|
||||||
|
Reference in New Issue
Block a user