mirror of
https://github.com/GAM-team/GAM.git
synced 2026-07-03 12:21:35 +00:00
Updated gam course <CourseID> create|update announcement
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
his document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
|
This document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
|
||||||
Skip the History section and start reading at Introduction.
|
Skip the History section and start reading at Introduction.
|
||||||
|
|
||||||
Items on the command line are space separated, when an actual space character is required, it will be indicated by <Space>.
|
Items on the command line are space separated, when an actual space character is required, it will be indicated by <Space>.
|
||||||
@@ -405,6 +405,11 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<ContactGroupItem> ::= <ContactGroupID>|<ContactGroupName>
|
<ContactGroupItem> ::= <ContactGroupID>|<ContactGroupName>
|
||||||
<CorporaAttribute> ::= alldrives|allteamdrives|domain|onlyteamdrives|user
|
<CorporaAttribute> ::= alldrives|allteamdrives|domain|onlyteamdrives|user
|
||||||
<CourseAlias> ::= <String>
|
<CourseAlias> ::= <String>
|
||||||
|
<CourseAnnouncementContent> ::=
|
||||||
|
((text <String>)|
|
||||||
|
(textfile <FileName> [charset <Charset>])|
|
||||||
|
(gdoc <UserGoogleDoc>)|
|
||||||
|
(gcsdoc <StorageBucketObjectName>))
|
||||||
<CourseAnnouncementID> ::= <Number>
|
<CourseAnnouncementID> ::= <Number>
|
||||||
<CourseAnnouncementState> ::= draft|published|deleted
|
<CourseAnnouncementState> ::= draft|published|deleted
|
||||||
<CourseID> ::= <Number>|d:<CourseAlias>
|
<CourseID> ::= <Number>|d:<CourseAlias>
|
||||||
@@ -3120,11 +3125,17 @@ 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>
|
||||||
|
|
||||||
|
<CourseAnnouncementContent> ::=
|
||||||
|
((text <String>)|
|
||||||
|
(textfile <FileName> [charset <Charset>])|
|
||||||
|
(gdoc <UserGoogleDoc>)|
|
||||||
|
(gcsdoc <StorageBucketObjectName>))
|
||||||
|
|
||||||
gam course <CourseID> create announcement
|
gam course <CourseID> create announcement
|
||||||
text <String> [scheduledtime <Time>] [state draft|published]
|
<CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
|
||||||
gam course <CourseID> remove announcement <CourseAnnouncementID>
|
gam course <CourseID> remove announcement <CourseAnnouncementID>
|
||||||
gam course <CourseID> update announcement <CourseAnnouncementID>
|
gam course <CourseID> update announcement <CourseAnnouncementID>
|
||||||
[text <String>] [scheduledtime <Time>] [state published]
|
[<CourseAnnouncementContent>] [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>
|
||||||
@@ -3141,10 +3152,10 @@ gam courses <CourseEntity> create|add alias <CourseAliasEntity>
|
|||||||
gam courses <CourseEntity> delete alias <CourseAliasEntity>
|
gam courses <CourseEntity> delete alias <CourseAliasEntity>
|
||||||
|
|
||||||
gam courses <CourseEntity> create announcement
|
gam courses <CourseEntity> create announcement
|
||||||
text <String> [scheduledtime <Time>] [state draft|published]
|
<CourseAnnouncementContent>> [scheduledtime <Time>] [state draft|published]
|
||||||
gam courses <CourseEntity> remove announcement <CourseAnnouncementIDEntity>
|
gam courses <CourseEntity> remove announcement <CourseAnnouncementIDEntity>
|
||||||
gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
|
gam courses <CourseEntity> update announcement <CourseAnnouncementIDEntity>
|
||||||
[text <String>] [scheduledtime <Time>] [state published]
|
[<CourseAnnouncementContent>] [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>
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
7.11.01
|
||||||
|
|
||||||
|
Updated `gam course <CourseID> create|update announcement` to accept input from
|
||||||
|
a literal string, a file or a Google Doc.
|
||||||
|
```
|
||||||
|
<CourseAnnouncementContent> ::=
|
||||||
|
((text <String>)|
|
||||||
|
(textfile <FileName> [charset <Charset>])|
|
||||||
|
(gdoc <UserGoogleDoc>)|
|
||||||
|
(gcsdoc <StorageBucketObjectName>))
|
||||||
|
```
|
||||||
|
|
||||||
7.11.00
|
7.11.00
|
||||||
|
|
||||||
Added commands to manage classroom/course announcements.
|
Added commands to manage classroom/course announcements.
|
||||||
|
|||||||
@@ -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.11.00'
|
__version__ = '7.11.01'
|
||||||
__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
|
||||||
@@ -634,7 +634,8 @@ def accessErrorMessage(cd, errMsg=None):
|
|||||||
cd = buildGAPIObject(API.DIRECTORY)
|
cd = buildGAPIObject(API.DIRECTORY)
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.customers(), 'get',
|
callGAPI(cd.customers(), 'get',
|
||||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customerKey=GC.Values[GC.CUSTOMER_ID], fields='id')
|
customerKey=GC.Values[GC.CUSTOMER_ID], fields='id')
|
||||||
except (GAPI.badRequest, GAPI.invalidInput):
|
except (GAPI.badRequest, GAPI.invalidInput):
|
||||||
return formatKeyValueList('',
|
return formatKeyValueList('',
|
||||||
@@ -671,14 +672,16 @@ def accessErrorExitNonDirectory(api, errMsg):
|
|||||||
''))
|
''))
|
||||||
|
|
||||||
def ClientAPIAccessDeniedExit(errMsg=None):
|
def ClientAPIAccessDeniedExit(errMsg=None):
|
||||||
stderrErrorMsg(Msg.API_ACCESS_DENIED)
|
if errMsg is None:
|
||||||
if errMsg:
|
stderrErrorMsg(Msg.API_ACCESS_DENIED)
|
||||||
|
missingScopes = API.getClientScopesSet(GM.Globals[GM.CURRENT_CLIENT_API])-GM.Globals[GM.CURRENT_CLIENT_API_SCOPES]
|
||||||
|
if missingScopes:
|
||||||
|
writeStderr(Msg.API_CHECK_CLIENT_AUTHORIZATION.format(GM.Globals[GM.OAUTH2_CLIENT_ID],
|
||||||
|
','.join(sorted(missingScopes))))
|
||||||
|
systemErrorExit(API_ACCESS_DENIED_RC, None)
|
||||||
|
else:
|
||||||
stderrErrorMsg(errMsg)
|
stderrErrorMsg(errMsg)
|
||||||
missingScopes = API.getClientScopesSet(GM.Globals[GM.CURRENT_CLIENT_API])-GM.Globals[GM.CURRENT_CLIENT_API_SCOPES]
|
systemErrorExit(API_ACCESS_DENIED_RC, Msg.REAUTHENTICATION_IS_NEEDED)
|
||||||
if missingScopes:
|
|
||||||
writeStderr(Msg.API_CHECK_CLIENT_AUTHORIZATION.format(GM.Globals[GM.OAUTH2_CLIENT_ID],
|
|
||||||
','.join(sorted(missingScopes))))
|
|
||||||
systemErrorExit(API_ACCESS_DENIED_RC, None)
|
|
||||||
|
|
||||||
def SvcAcctAPIAccessDenied():
|
def SvcAcctAPIAccessDenied():
|
||||||
_getSvcAcctData()
|
_getSvcAcctData()
|
||||||
@@ -4458,6 +4461,8 @@ def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0):
|
|||||||
errMsg.startswith('invalid_request: Invalid impersonation "sub" field')):
|
errMsg.startswith('invalid_request: Invalid impersonation "sub" field')):
|
||||||
if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
|
if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
|
||||||
ClientAPIAccessDeniedExit()
|
ClientAPIAccessDeniedExit()
|
||||||
|
# 403 Forbidden, API disabled, user not enabled
|
||||||
|
# 400 Bad Request, user not defined
|
||||||
if softErrors:
|
if softErrors:
|
||||||
entityActionFailedWarning([Ent.USER, GM.Globals[GM.CURRENT_SVCACCT_USER], Ent.USER, None], errMsg, i, count)
|
entityActionFailedWarning([Ent.USER, GM.Globals[GM.CURRENT_SVCACCT_USER], Ent.USER, None], errMsg, i, count)
|
||||||
return None
|
return None
|
||||||
@@ -4465,6 +4470,7 @@ def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0):
|
|||||||
if errMsg in API.OAUTH2_UNAUTHORIZED_ERRORS:
|
if errMsg in API.OAUTH2_UNAUTHORIZED_ERRORS:
|
||||||
if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
|
if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
|
||||||
ClientAPIAccessDeniedExit()
|
ClientAPIAccessDeniedExit()
|
||||||
|
# 401 Unauthorized, API disabled, user enabled
|
||||||
if softErrors:
|
if softErrors:
|
||||||
if displayError:
|
if displayError:
|
||||||
apiOrScopes = API.getAPIName(GM.Globals[GM.CURRENT_SVCACCT_API]) if GM.Globals[GM.CURRENT_SVCACCT_API] else ','.join(sorted(GM.Globals[GM.CURRENT_SVCACCT_API_SCOPES]))
|
apiOrScopes = API.getAPIName(GM.Globals[GM.CURRENT_SVCACCT_API]) if GM.Globals[GM.CURRENT_SVCACCT_API] else ','.join(sorted(GM.Globals[GM.CURRENT_SVCACCT_API_SCOPES]))
|
||||||
@@ -6515,7 +6521,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
|
|||||||
printGettingAllEntityItemsForWhom(Ent.TEACHER, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
printGettingAllEntityItemsForWhom(Ent.TEACHER, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
||||||
result = callGAPIpages(courseInfo['croom'].courses().teachers(), 'list', 'teachers',
|
result = callGAPIpages(courseInfo['croom'].courses().teachers(), 'list', 'teachers',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
courseId=courseId, fields='nextPageToken,teachers/profile/emailAddress',
|
courseId=courseId, fields='nextPageToken,teachers/profile/emailAddress',
|
||||||
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
||||||
@@ -6528,7 +6535,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
|
|||||||
printGettingAllEntityItemsForWhom(Ent.STUDENT, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
printGettingAllEntityItemsForWhom(Ent.STUDENT, removeCourseIdScope(courseId), entityType=Ent.COURSE)
|
||||||
result = callGAPIpages(courseInfo['croom'].courses().students(), 'list', 'students',
|
result = callGAPIpages(courseInfo['croom'].courses().students(), 'list', 'students',
|
||||||
pageMessage=getPageMessageForWhom(),
|
pageMessage=getPageMessageForWhom(),
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
courseId=courseId, fields='nextPageToken,students/profile/emailAddress',
|
courseId=courseId, fields='nextPageToken,students/profile/emailAddress',
|
||||||
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
|
||||||
@@ -6544,8 +6552,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
|
|||||||
entityActionNotPerformedWarning([Ent.COURSE, removeCourseIdScope(courseId)], str(e))
|
entityActionNotPerformedWarning([Ent.COURSE, removeCourseIdScope(courseId)], str(e))
|
||||||
GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE] = True
|
GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE] = True
|
||||||
break
|
break
|
||||||
except (GAPI.forbidden, GAPI.badRequest):
|
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.badRequest) as e:
|
||||||
ClientAPIAccessDeniedExit()
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
elif entityType == Cmd.ENTITY_CROS:
|
elif entityType == Cmd.ENTITY_CROS:
|
||||||
buildGAPIObject(API.DIRECTORY)
|
buildGAPIObject(API.DIRECTORY)
|
||||||
result = convertEntityToList(entity)
|
result = convertEntityToList(entity)
|
||||||
@@ -9023,7 +9031,7 @@ class CSVPrintFile():
|
|||||||
normalizeSortHeaders()
|
normalizeSortHeaders()
|
||||||
if self.outputTranspose:
|
if self.outputTranspose:
|
||||||
newRows = []
|
newRows = []
|
||||||
newTitlesList = [i for i in range(len(self.rows)+1)]
|
newTitlesList = list(range(len(self.rows) + 1))
|
||||||
for title in titlesList:
|
for title in titlesList:
|
||||||
i = 0
|
i = 0
|
||||||
newRow = {i: title}
|
newRow = {i: title}
|
||||||
@@ -16010,8 +16018,9 @@ def doCreateDomainAlias():
|
|||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.domainAliases(), 'insert',
|
callGAPI(cd.domainAliases(), 'insert',
|
||||||
throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.DUPLICATE, GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.DUPLICATE, GAPI.INVALID, GAPI.CONFLICT,
|
||||||
GAPI.FORBIDDEN, GAPI.CONFLICT],
|
GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
||||||
entityActionPerformed([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']])
|
entityActionPerformed([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']])
|
||||||
except GAPI.domainNotFound:
|
except GAPI.domainNotFound:
|
||||||
@@ -16020,8 +16029,10 @@ def doCreateDomainAlias():
|
|||||||
entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], Msg.DUPLICATE)
|
entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], Msg.DUPLICATE)
|
||||||
except (GAPI.invalid, GAPI.conflict) as e:
|
except (GAPI.invalid, GAPI.conflict) as e:
|
||||||
entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], str(e))
|
entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], str(e))
|
||||||
except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
# gam delete domainalias|aliasdomain <DomainAlias>
|
# gam delete domainalias|aliasdomain <DomainAlias>
|
||||||
def doDeleteDomainAlias():
|
def doDeleteDomainAlias():
|
||||||
@@ -16030,13 +16041,16 @@ def doDeleteDomainAlias():
|
|||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.domainAliases(), 'delete',
|
callGAPI(cd.domainAliases(), 'delete',
|
||||||
throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
|
customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
|
||||||
entityActionPerformed([Ent.DOMAIN_ALIAS, domainAliasName])
|
entityActionPerformed([Ent.DOMAIN_ALIAS, domainAliasName])
|
||||||
except GAPI.domainAliasNotFound:
|
except GAPI.domainAliasNotFound:
|
||||||
entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
|
entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
|
||||||
except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
DOMAIN_TIME_OBJECTS = {'creationTime'}
|
DOMAIN_TIME_OBJECTS = {'creationTime'}
|
||||||
DOMAIN_ALIAS_PRINT_ORDER = ['parentDomainName', 'creationTime', 'verified']
|
DOMAIN_ALIAS_PRINT_ORDER = ['parentDomainName', 'creationTime', 'verified']
|
||||||
@@ -16064,14 +16078,17 @@ def doInfoDomainAlias():
|
|||||||
FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
|
FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
|
||||||
try:
|
try:
|
||||||
result = callGAPI(cd.domainAliases(), 'get',
|
result = callGAPI(cd.domainAliases(), 'get',
|
||||||
throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
|
customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
|
||||||
aliasSkipObjects = DOMAIN_ALIAS_SKIP_OBJECTS
|
aliasSkipObjects = DOMAIN_ALIAS_SKIP_OBJECTS
|
||||||
_showDomainAlias(result, FJQC, aliasSkipObjects)
|
_showDomainAlias(result, FJQC, aliasSkipObjects)
|
||||||
except GAPI.domainAliasNotFound:
|
except GAPI.domainAliasNotFound:
|
||||||
entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
|
entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
|
||||||
except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
def _printDomain(domain, csvPF):
|
def _printDomain(domain, csvPF):
|
||||||
row = {}
|
row = {}
|
||||||
@@ -16107,7 +16124,8 @@ def doPrintShowDomainAliases():
|
|||||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||||
try:
|
try:
|
||||||
domainAliases = callGAPIitems(cd.domainAliases(), 'list', 'domainAliases',
|
domainAliases = callGAPIitems(cd.domainAliases(), 'list', 'domainAliases',
|
||||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID])
|
customer=GC.Values[GC.CUSTOMER_ID])
|
||||||
count = len(domainAliases)
|
count = len(domainAliases)
|
||||||
if showItemCountOnly:
|
if showItemCountOnly:
|
||||||
@@ -16125,8 +16143,10 @@ def doPrintShowDomainAliases():
|
|||||||
csvPF.WriteRowNoFilter({'domainAliasName': domainAlias['domainAliasName'],
|
csvPF.WriteRowNoFilter({'domainAliasName': domainAlias['domainAliasName'],
|
||||||
'JSON': json.dumps(cleanJSON(domainAlias, timeObjects=DOMAIN_TIME_OBJECTS),
|
'JSON': json.dumps(cleanJSON(domainAlias, timeObjects=DOMAIN_TIME_OBJECTS),
|
||||||
ensure_ascii=False, sort_keys=True)})
|
ensure_ascii=False, sort_keys=True)})
|
||||||
except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
if csvPF:
|
if csvPF:
|
||||||
csvPF.writeCSVfile('Domain Aliases')
|
csvPF.writeCSVfile('Domain Aliases')
|
||||||
|
|
||||||
@@ -16137,15 +16157,19 @@ def doCreateDomain():
|
|||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.domains(), 'insert',
|
callGAPI(cd.domains(), 'insert',
|
||||||
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.CONFLICT],
|
throwReasons=[GAPI.DUPLICATE, GAPI.CONFLICT,
|
||||||
|
GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
||||||
entityActionPerformed([Ent.DOMAIN, body['domainName']])
|
entityActionPerformed([Ent.DOMAIN, body['domainName']])
|
||||||
except GAPI.duplicate:
|
except GAPI.duplicate:
|
||||||
entityDuplicateWarning([Ent.DOMAIN, body['domainName']])
|
entityDuplicateWarning([Ent.DOMAIN, body['domainName']])
|
||||||
except GAPI.conflict as e:
|
except GAPI.conflict as e:
|
||||||
entityActionFailedWarning([Ent.DOMAIN, body['domainName']], str(e))
|
entityActionFailedWarning([Ent.DOMAIN, body['domainName']], str(e))
|
||||||
except (GAPI.domainNotFound, GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.domainNotFound, GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
# gam update domain <DomainName> primary
|
# gam update domain <DomainName> primary
|
||||||
def doUpdateDomain():
|
def doUpdateDomain():
|
||||||
@@ -16162,13 +16186,17 @@ def doUpdateDomain():
|
|||||||
missingArgumentExit('primary')
|
missingArgumentExit('primary')
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.customers(), 'update',
|
callGAPI(cd.customers(), 'update',
|
||||||
throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT],
|
throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.BAD_REQUEST,
|
||||||
|
GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_INPUT,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customerKey=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
customerKey=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
|
||||||
entityActionPerformedMessage([Ent.DOMAIN, domainName], Msg.NOW_THE_PRIMARY_DOMAIN)
|
entityActionPerformedMessage([Ent.DOMAIN, domainName], Msg.NOW_THE_PRIMARY_DOMAIN)
|
||||||
except GAPI.domainNotVerifiedSecondary:
|
except GAPI.domainNotVerifiedSecondary:
|
||||||
entityActionFailedWarning([Ent.DOMAIN, domainName], Msg.DOMAIN_NOT_VERIFIED_SECONDARY)
|
entityActionFailedWarning([Ent.DOMAIN, domainName], Msg.DOMAIN_NOT_VERIFIED_SECONDARY)
|
||||||
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalidInput) as e:
|
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.invalidInput) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
# gam delete domain <DomainName>
|
# gam delete domain <DomainName>
|
||||||
def doDeleteDomain():
|
def doDeleteDomain():
|
||||||
@@ -16177,11 +16205,14 @@ def doDeleteDomain():
|
|||||||
checkForExtraneousArguments()
|
checkForExtraneousArguments()
|
||||||
try:
|
try:
|
||||||
callGAPI(cd.domains(), 'delete',
|
callGAPI(cd.domains(), 'delete',
|
||||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
customer=GC.Values[GC.CUSTOMER_ID], domainName=domainName)
|
customer=GC.Values[GC.CUSTOMER_ID], domainName=domainName)
|
||||||
entityActionPerformed([Ent.DOMAIN, domainName])
|
entityActionPerformed([Ent.DOMAIN, domainName])
|
||||||
except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
|
except (GAPI.badRequest, GAPI.notFound) as e:
|
||||||
accessErrorExit(cd, str(e))
|
accessErrorExit(cd, str(e))
|
||||||
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
|
|
||||||
CUSTOMER_LICENSE_MAP = {
|
CUSTOMER_LICENSE_MAP = {
|
||||||
'accounts:num_users': 'Total Users',
|
'accounts:num_users': 'Total Users',
|
||||||
@@ -16210,7 +16241,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
result = callGAPI(rep.customerUsageReports(), 'get',
|
result = callGAPI(rep.customerUsageReports(), 'get',
|
||||||
throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN],
|
throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
date=tryDate, customerId=customerInfo['id'],
|
date=tryDate, customerId=customerInfo['id'],
|
||||||
fields='warnings,usageReports', parameters=parameters)
|
fields='warnings,usageReports', parameters=parameters)
|
||||||
usageReports = numUsersAvailable(result)
|
usageReports = numUsersAvailable(result)
|
||||||
@@ -16228,8 +16259,8 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
|
|||||||
if not tryDate:
|
if not tryDate:
|
||||||
return
|
return
|
||||||
continue
|
continue
|
||||||
except GAPI.forbidden:
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
return
|
ClientAPIAccessDeniedExit(str(e))
|
||||||
if not FJQC.formatJSON:
|
if not FJQC.formatJSON:
|
||||||
printKeyValueList([f'User counts as of {tryDate}:'])
|
printKeyValueList([f'User counts as of {tryDate}:'])
|
||||||
Ind.Increment()
|
Ind.Increment()
|
||||||
@@ -47688,7 +47719,8 @@ def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
|
|||||||
if courseId not in coursesInfo:
|
if courseId not in coursesInfo:
|
||||||
try:
|
try:
|
||||||
course = callGAPI(croom.courses(), 'get',
|
course = callGAPI(croom.courses(), 'get',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
|
||||||
|
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||||
id=courseId, fields='name,ownerId')
|
id=courseId, fields='name,ownerId')
|
||||||
if useOwnerAccess:
|
if useOwnerAccess:
|
||||||
@@ -47699,9 +47731,9 @@ def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
|
|||||||
coursesInfo[ciCourseId] = {'name': course['name'], 'croom': ocroom}
|
coursesInfo[ciCourseId] = {'name': course['name'], 'croom': ocroom}
|
||||||
except GAPI.notFound:
|
except GAPI.notFound:
|
||||||
entityDoesNotExistWarning(Ent.COURSE, courseId)
|
entityDoesNotExistWarning(Ent.COURSE, courseId)
|
||||||
except (GAPI.permissionDenied, GAPI.serviceNotAvailable) as e:
|
except GAPI.serviceNotAvailable as e:
|
||||||
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
entityActionFailedWarning([Ent.COURSE, courseId], str(e))
|
||||||
except GAPI.forbidden:
|
except (GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||||
ClientAPIAccessDeniedExit()
|
ClientAPIAccessDeniedExit()
|
||||||
return 0, len(coursesInfo), coursesInfo
|
return 0, len(coursesInfo), coursesInfo
|
||||||
|
|
||||||
@@ -48931,43 +48963,73 @@ def doPrintCourseParticipants():
|
|||||||
csvPF.writeCSVfile('Course Participants')
|
csvPF.writeCSVfile('Course Participants')
|
||||||
|
|
||||||
def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
|
def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
|
||||||
|
def _addIdToResponse(response, riItem):
|
||||||
|
if addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
respId = response.get('id', '')
|
||||||
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
|
respId = response.get('topicId', '')
|
||||||
|
else:
|
||||||
|
respId = ''
|
||||||
|
if respId:
|
||||||
|
return riItem + f'({respId})'
|
||||||
|
return riItem
|
||||||
|
|
||||||
_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}
|
||||||
def _callbackAddItemsToCourse(request_id, _, exception):
|
def _callbackAddItemsToCourse(request_id, response, exception):
|
||||||
ri = request_id.splitlines()
|
ri = request_id.splitlines()
|
||||||
|
if addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
mg = re.match(r"^{'text': '(.+)'}$", ri[RI_ITEM])
|
||||||
|
if mg:
|
||||||
|
riText = mg.group(1)
|
||||||
|
else:
|
||||||
|
riText = ''
|
||||||
|
if len(riText) > 100:
|
||||||
|
riItem = riText[0:100]+'...'
|
||||||
|
else:
|
||||||
|
riItem = riText
|
||||||
|
else:
|
||||||
|
riItem = ri[RI_ITEM]
|
||||||
if exception is None:
|
if exception is None:
|
||||||
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
riItem = _addIdToResponse(response, riItem)
|
||||||
|
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], addType, riItem], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
else:
|
else:
|
||||||
http_status, reason, message = checkGAPIError(exception)
|
http_status, reason, message = checkGAPIError(exception)
|
||||||
if (reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}) and ((reason != GAPI.NOT_FOUND) or (ri[RI_ROLE] == Ent.COURSE_ALIAS)):
|
if (reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}) and ((reason != GAPI.NOT_FOUND) or (addType == Ent.COURSE_ALIAS)):
|
||||||
if reason in [GAPI.FORBIDDEN, GAPI.BACKEND_ERROR]:
|
if reason in [GAPI.FORBIDDEN, GAPI.BACKEND_ERROR]:
|
||||||
errMsg = getPhraseDNEorSNA(ri[RI_ITEM])
|
errMsg = getPhraseDNEorSNA(riItem)
|
||||||
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 (addType 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]} addType {Ent.Singular(ri[RI_ROLE])}'
|
errMsg += f' Add external user with: gam user {riItem} create classroominvitation courses {ri[RI_ENTITY]} addType {Ent.Singular(addType)}'
|
||||||
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], addType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
return
|
return
|
||||||
waitOnFailure(1, 10, reason, message)
|
waitOnFailure(1, 10, reason, message)
|
||||||
|
if addType in {Ent.STUDENT, Ent.TEACHER, Ent.COURSE_TOPIC}:
|
||||||
|
rbody = {attribute: riItem}
|
||||||
|
elif addType == Ent.COURSE_ALIAS:
|
||||||
|
rbody = {attribute: addCourseAliasScope(riItem)}
|
||||||
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
|
rbody = ri[RI_ITEM]
|
||||||
try:
|
try:
|
||||||
callGAPI(service, 'create',
|
result = callGAPI(service, 'create',
|
||||||
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR,
|
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR,
|
||||||
GAPI.ALREADY_EXISTS, GAPI.FAILED_PRECONDITION,
|
GAPI.ALREADY_EXISTS, GAPI.FAILED_PRECONDITION,
|
||||||
GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
|
GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
|
||||||
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=rbody, fields=returnFields)
|
||||||
body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
|
riItem = _addIdToResponse(result, riItem)
|
||||||
fields='')
|
|
||||||
except (GAPI.notFound, GAPI.backendError, GAPI.forbidden):
|
except (GAPI.notFound, GAPI.backendError, GAPI.forbidden):
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], getPhraseDNEorSNA(ri[RI_ITEM]), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], getPhraseDNEorSNA(riItem), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except GAPI.alreadyExists:
|
except GAPI.alreadyExists:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.DUPLICATE, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], Msg.DUPLICATE, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except GAPI.failedPrecondition:
|
except GAPI.failedPrecondition:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.NOT_ALLOWED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], Msg.NOT_ALLOWED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
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], addType, riItem], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
|
|
||||||
|
returnFields = ''
|
||||||
if addType == Ent.STUDENT:
|
if addType == Ent.STUDENT:
|
||||||
service = croom.courses().students()
|
service = croom.courses().students()
|
||||||
attribute = 'userId'
|
attribute = 'userId'
|
||||||
@@ -48980,16 +49042,18 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
|
|||||||
elif addType == Ent.COURSE_TOPIC:
|
elif addType == Ent.COURSE_TOPIC:
|
||||||
service = croom.courses().topics()
|
service = croom.courses().topics()
|
||||||
attribute = 'name'
|
attribute = 'name'
|
||||||
|
returnFields = 'topicId'
|
||||||
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
else: # addType == Ent.COURSE_ANNOUNCEMENT:
|
||||||
service = croom.courses().announcements()
|
service = croom.courses().announcements()
|
||||||
attribute = 'text'
|
attribute = 'text'
|
||||||
|
returnFields = 'id'
|
||||||
method = getattr(service, 'create')
|
method = getattr(service, 'create')
|
||||||
Act.Set(Act.ADD)
|
Act.Set(Act.ADD)
|
||||||
jcount = len(addItems)
|
jcount = len(addItems)
|
||||||
noScopeCourseId = removeCourseIdScope(courseId)
|
noScopeCourseId = removeCourseIdScope(courseId)
|
||||||
entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, addType, 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', returnFields)]+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
|
||||||
@@ -49021,34 +49085,37 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeItems, removeTy
|
|||||||
GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
|
GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
|
||||||
def _callbackRemoveItemsFromCourse(request_id, _, exception):
|
def _callbackRemoveItemsFromCourse(request_id, _, exception):
|
||||||
ri = request_id.splitlines()
|
ri = request_id.splitlines()
|
||||||
|
riItem = ri[RI_ITEM]
|
||||||
if exception is None:
|
if exception is None:
|
||||||
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
else:
|
else:
|
||||||
http_status, reason, message = checkGAPIError(exception)
|
http_status, reason, message = checkGAPIError(exception)
|
||||||
if reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}:
|
if reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}:
|
||||||
if reason == GAPI.NOT_FOUND and ri[RI_ROLE] != Ent.COURSE_ALIAS:
|
if reason == GAPI.NOT_FOUND and removeType != Ent.COURSE_ALIAS:
|
||||||
errMsg = f'{Msg.NOT_A} {Ent.Singular(ri[RI_ROLE])}'
|
errMsg = f'{Msg.NOT_A} {Ent.Singular(removeType)}'
|
||||||
else:
|
else:
|
||||||
errMsg = getHTTPError(_REMOVE_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
|
errMsg = getHTTPError(_REMOVE_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
|
||||||
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], removeType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
return
|
return
|
||||||
waitOnFailure(1, 10, reason, message)
|
waitOnFailure(1, 10, reason, message)
|
||||||
|
if removeType in {Ent.STUDENT, Ent.TEACHER, Ent.COURSE_TOPIC, Ent.COURSE_ANNOUNCEMENT}:
|
||||||
|
rbody = {attribute: riItem}
|
||||||
|
else: # removeType == Ent.COURSE_ALIAS:
|
||||||
|
rbody = {attribute: addCourseAliasScope(riItem)}
|
||||||
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.FAILED_PRECONDITION],
|
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=rbody, fields='')
|
||||||
body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
|
|
||||||
fields='')
|
|
||||||
except GAPI.notFound:
|
except GAPI.notFound:
|
||||||
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.DOES_NOT_EXIST, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], Msg.DOES_NOT_EXIST, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except GAPI.forbidden:
|
except GAPI.forbidden:
|
||||||
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], removeType, riItem], 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], removeType, riItem], Msg.PERMISSION_DENIED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
except (GAPI.quotaExceeded, GAPI.serviceNotAvailable, GAPI.failedPrecondition) 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], removeType, riItem], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||||
|
|
||||||
if removeType == Ent.STUDENT:
|
if removeType == Ent.STUDENT:
|
||||||
service = croom.courses().students()
|
service = croom.courses().students()
|
||||||
@@ -49121,8 +49188,8 @@ def getCourseAnnouncement(createCmd):
|
|||||||
body = {}
|
body = {}
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
myarg = getArgument()
|
myarg = getArgument()
|
||||||
if myarg == 'text':
|
if myarg in SORF_TEXT_ARGUMENTS:
|
||||||
body['text'] = getString(Cmd.OB_STRING, minLen=1, maxLen=30000)
|
body['text'] = getStringOrFile(myarg, minLen=1, unescapeCRLF=True)[0]
|
||||||
elif myarg == 'scheduledtime':
|
elif myarg == 'scheduledtime':
|
||||||
body['scheduledTime'] = getTimeOrDeltaFromNow()
|
body['scheduledTime'] = getTimeOrDeltaFromNow()
|
||||||
elif myarg == 'state':
|
elif myarg == 'state':
|
||||||
@@ -49160,9 +49227,9 @@ 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
|
# gam courses <CourseEntity> create announcement
|
||||||
# text <String> [scheduledtime <Time>] [state draft|published]
|
# <CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
|
||||||
# gam course <CourseID> create announcement
|
# gam course <CourseID> create announcement
|
||||||
# text <String> [scheduledtime <Time>] [state draft|published]
|
# <CourseAnnouncementContent> [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>
|
||||||
@@ -49270,9 +49337,9 @@ def doCourseRemoveItems(courseIdList, getEntityListArg):
|
|||||||
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, removeType)
|
_batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, removeType)
|
||||||
|
|
||||||
# gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
|
# gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
|
||||||
# [text <String>] [scheduledtime <Time>] [state published]
|
# [<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
|
||||||
# gam course <CourseID> update announcement <CourseAnnouncementID>
|
# gam course <CourseID> update announcement <CourseAnnouncementID>
|
||||||
# [text <String>] [scheduledtime <Time>] [state published]
|
# [<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
|
||||||
# gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
|
# gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
|
||||||
# gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
|
# gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
|
||||||
def doCourseUpdateItems(courseIdList, getEntityListArg):
|
def doCourseUpdateItems(courseIdList, getEntityListArg):
|
||||||
|
|||||||
Reference in New Issue
Block a user