This commit is contained in:
Jay Lee
2017-10-20 11:15:07 -04:00
2 changed files with 54 additions and 76 deletions

View File

@ -824,7 +824,6 @@ gam show guardian|guardians [invitedguardian <EmailAddress>] [student <StudentIt
gam print guardian|guardians [todrive] [invitedguardian <EmailAddress>] [student <StudentItem>] [invitations [states <GuardianStateList>]] [<UserTypeEntity>] gam print guardian|guardians [todrive] [invitedguardian <EmailAddress>] [student <StudentItem>] [invitations [states <GuardianStateList>]] [<UserTypeEntity>]
gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem> gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem>
gam printer register
gam update printer <PrinterID> <PrinterAttributes>+ gam update printer <PrinterID> <PrinterAttributes>+
gam delete printer <PrinterID> gam delete printer <PrinterID>
gam info printer <PrinterID> [everything] gam info printer <PrinterID> [everything]

View File

@ -46,9 +46,9 @@ import googleapiclient.discovery
import googleapiclient.errors import googleapiclient.errors
import googleapiclient.http import googleapiclient.http
import httplib2 import httplib2
import oauth2client.client
import google.oauth2.service_account import google.oauth2.service_account
import google_auth_httplib2 import google_auth_httplib2
import oauth2client.client
import oauth2client.file import oauth2client.file
import oauth2client.tools import oauth2client.tools
@ -156,6 +156,16 @@ def getCharSet(i):
return (i, GC_Values.get(GC_CHARSET, GM_Globals[GM_SYS_ENCODING])) return (i, GC_Values.get(GC_CHARSET, GM_Globals[GM_SYS_ENCODING]))
return (i+2, sys.argv[i+1]) return (i+2, sys.argv[i+1])
def removeCourseIdScope(courseId):
if courseId.startswith(u'd:'):
return courseId[2:]
return courseId
def addCourseIdScope(courseId):
if not courseId.isdigit() and courseId[:2] != u'd:':
return u'd:{0}'.format(courseId)
return courseId
def getString(i, item, emptyOK=False, optional=False): def getString(i, item, emptyOK=False, optional=False):
if i < len(sys.argv): if i < len(sys.argv):
argstr = sys.argv[i] argstr = sys.argv[i]
@ -987,12 +997,12 @@ def getTimeOrDeltaFromNow(time_string):
else: else:
return (datetime.datetime.utcnow() + deltaTime).isoformat() + u'Z' return (datetime.datetime.utcnow() + deltaTime).isoformat() + u'Z'
def buildGAPIServiceObject(api, act_as, use_scopes=None): def buildGAPIServiceObject(api, act_as, showAuthError=True):
http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL],
cache=GM_Globals[GM_CACHE_DIR]) cache=GM_Globals[GM_CACHE_DIR])
service = getService(api, http) service = getService(api, http)
GM_Globals[GM_CURRENT_API_USER] = act_as GM_Globals[GM_CURRENT_API_USER] = act_as
GM_Globals[GM_CURRENT_API_SCOPES] = use_scopes or API_SCOPE_MAPPING[api] GM_Globals[GM_CURRENT_API_SCOPES] = API_SCOPE_MAPPING[api]
credentials = getSvcAcctCredentials(GM_Globals[GM_CURRENT_API_SCOPES], act_as) credentials = getSvcAcctCredentials(GM_Globals[GM_CURRENT_API_SCOPES], act_as)
request = google_auth_httplib2.Request(http) request = google_auth_httplib2.Request(http)
try: try:
@ -1001,6 +1011,7 @@ def buildGAPIServiceObject(api, act_as, use_scopes=None):
except httplib2.ServerNotFoundError as e: except httplib2.ServerNotFoundError as e:
systemErrorExit(4, e) systemErrorExit(4, e)
except google.auth.exceptions.RefreshError as e: except google.auth.exceptions.RefreshError as e:
if showAuthError:
stderrErrorMsg(u'User {0}: {1}'.format(GM_Globals[GM_CURRENT_API_USER], str(e[0]))) stderrErrorMsg(u'User {0}: {1}'.format(GM_Globals[GM_CURRENT_API_USER], str(e[0])))
return handleOAuthTokenError(str(e[0]), True) return handleOAuthTokenError(str(e[0]), True)
return service return service
@ -1022,11 +1033,10 @@ def buildCalendarGAPIObject(calname):
return (calendarId, buildGAPIServiceObject(u'calendar', calendarId)) return (calendarId, buildGAPIServiceObject(u'calendar', calendarId))
def buildCalendarDataGAPIObject(calname): def buildCalendarDataGAPIObject(calname):
calendarId, cal = buildCalendarGAPIObject(calname) calendarId = normalizeCalendarId(calname)
try:
# Force service account token request. If we fail fall back to using admin for authentication # Force service account token request. If we fail fall back to using admin for authentication
cal._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) cal = buildGAPIServiceObject(u'calendar', calendarId, False)
except oauth2client.client.HttpAccessTokenRefreshError: if cal is None:
_, cal = buildCalendarGAPIObject(_getValueFromOAuth(u'email')) _, cal = buildCalendarGAPIObject(_getValueFromOAuth(u'email'))
return (calendarId, cal) return (calendarId, cal)
@ -1272,33 +1282,32 @@ def showReport():
def watchGmail(users): def watchGmail(users):
cs_data = readFile(GC_Values[GC_CLIENT_SECRETS_JSON], mode=u'rb', continueOnError=True, displayError=True, encoding=None) cs_data = readFile(GC_Values[GC_CLIENT_SECRETS_JSON], mode=u'rb', continueOnError=True, displayError=True, encoding=None)
cs_json = json.loads(cs_data) cs_json = json.loads(cs_data)
project = cs_json[u'installed'][u'project_id'] project = u'projects/{0}'.format(cs_json[u'installed'][u'project_id'])
topic = None gamTopics = project+u'/topics/gam-pubsub-gmail-'
gamSubscriptions = project+u'/subscriptions/gam-pubsub-gmail-'
pubsub = buildGAPIObject(u'pubsub') pubsub = buildGAPIObject(u'pubsub')
topics = callGAPIpages(pubsub.projects().topics(), u'list', items=u'topics', project=u'projects/%s' % project) topics = callGAPIpages(pubsub.projects().topics(), u'list', items=u'topics', project=project)
for atopic in topics: for atopic in topics:
if atopic[u'name'].startswith(u'projects/%s/topics/gam-pubsub-gmail-' % project): if atopic[u'name'].startswith(gamTopics):
topic = atopic[u'name'] topic = atopic[u'name']
break break
if not topic: else:
topic = u'projects/%s/topics/gam-pubsub-gmail-%s' % (project, uuid.uuid4()) topic = gamTopics+uuid.uuid4()
callGAPI(pubsub.projects().topics(), u'create', name=topic, body={}) callGAPI(pubsub.projects().topics(), u'create', name=topic, body={})
body = {u'policy': {u'bindings': [{u'members': [u'serviceAccount:gmail-api-push@system.gserviceaccount.com'], u'role': u'roles/pubsub.editor'}]}} body = {u'policy': {u'bindings': [{u'members': [u'serviceAccount:gmail-api-push@system.gserviceaccount.com'], u'role': u'roles/pubsub.editor'}]}}
callGAPI(pubsub.projects().topics(), u'setIamPolicy', resource=topic, body=body) callGAPI(pubsub.projects().topics(), u'setIamPolicy', resource=topic, body=body)
subscription = None
subscriptions = callGAPIpages(pubsub.projects().topics().subscriptions(), u'list', items=u'subscriptions', topic=topic) subscriptions = callGAPIpages(pubsub.projects().topics().subscriptions(), u'list', items=u'subscriptions', topic=topic)
for asubscription in subscriptions: for asubscription in subscriptions:
if asubscription.startswith(u'projects/%s/subscriptions/gam-pubsub-gmail-' % project): if asubscription.startswith(gamSubscriptions):
subscription = asubscription subscription = asubscription
break break
if not subscription: else:
subscription = u'projects/%s/subscriptions/gam-pubsub-gmail-%s' % (project, uuid.uuid4()) subscription = gamSubscriptions+uuid.uuid4()
sub_body = {u'topic': topic} callGAPI(pubsub.projects().subscriptions(), u'create', name=subscription, body={u'topic': topic})
sub_result = callGAPI(pubsub.projects().subscriptions(), u'create', name=subscription, body=sub_body)
gmails = {} gmails = {}
for user in users: for user in users:
gmails[user] = {u'g': buildGmailGAPIObject(user)[1]} gmails[user] = {u'g': buildGmailGAPIObject(user)[1]}
watch_result = callGAPI(gmails[user][u'g'].users(), u'watch', userId=u'me', body={u'topicName': topic}) callGAPI(gmails[user][u'g'].users(), u'watch', userId=u'me', body={u'topicName': topic})
gmails[user]['seen_historyId'] = callGAPI(gmails[user][u'g'].users(), u'getProfile', userId=u'me', fields=u'historyId')[u'historyId'] gmails[user]['seen_historyId'] = callGAPI(gmails[user][u'g'].users(), u'getProfile', userId=u'me', fields=u'historyId')[u'historyId']
print 'Watching for events...' print 'Watching for events...'
while True: while True:
@ -1464,36 +1473,26 @@ def deleteDelegate(users):
def doAddCourseParticipant(): def doAddCourseParticipant():
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
courseId = sys.argv[2] courseId = addCourseIdScope(sys.argv[2])
body_attribute = u'userId'
if len(courseId) < 3 or (not courseId.isdigit() and courseId[:2] != u'd:'):
courseId = u'd:%s' % courseId
participant_type = sys.argv[4].lower() participant_type = sys.argv[4].lower()
new_id = sys.argv[5] new_id = sys.argv[5]
if participant_type in [u'teacher', u'teachers']: if participant_type in [u'teacher', u'teachers']:
service = croom.courses().teachers() service = croom.courses().teachers()
body = {u'userId': new_id}
elif participant_type in [u'students', u'student']: elif participant_type in [u'students', u'student']:
service = croom.courses().students() service = croom.courses().students()
body = {u'userId': new_id}
elif participant_type in [u'alias']: elif participant_type in [u'alias']:
service = croom.courses().aliases() service = croom.courses().aliases()
body_attribute = u'alias' body = {u'alias': addCourseIdScope(new_id)}
if new_id[1] != u':':
new_id = u'd:%s' % new_id
else: else:
print u'ERROR: %s is not a valid argument to "gam course ID add"' % participant_type print u'ERROR: %s is not a valid argument to "gam course ID add"' % participant_type
sys.exit(2) sys.exit(2)
body = {body_attribute: new_id}
callGAPI(service, u'create', courseId=courseId, body=body) callGAPI(service, u'create', courseId=courseId, body=body)
if courseId[:2] == u'd:': print u'Added %s as a %s of course %s' % (removeCourseIdScope(new_id), participant_type, removeCourseIdScope(courseId))
courseId = courseId[2:]
if new_id[:2] == u'd:':
new_id = new_id[2:]
print u'Added %s as a %s of course %s' % (new_id, participant_type, courseId)
def doSyncCourseParticipants(): def doSyncCourseParticipants():
courseId = sys.argv[2] courseId = addCourseIdScope(sys.argv[2])
if not courseId.isdigit() and courseId[:2] != u'd:':
courseId = u'd:%s' % courseId
participant_type = sys.argv[4].lower() participant_type = sys.argv[4].lower()
diff_entity_type = sys.argv[5] diff_entity_type = sys.argv[5]
diff_entity = sys.argv[6] diff_entity = sys.argv[6]
@ -1516,38 +1515,27 @@ def doSyncCourseParticipants():
def doDelCourseParticipant(): def doDelCourseParticipant():
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
courseId = sys.argv[2] courseId = addCourseIdScope(sys.argv[2])
if not courseId.isdigit() and courseId[:2] != u'd:':
courseId = u'd:%s' % courseId
participant_type = sys.argv[4].lower() participant_type = sys.argv[4].lower()
remove_id = sys.argv[5] remove_id = sys.argv[5]
kwargs = {}
if participant_type in [u'teacher', u'teachers']: if participant_type in [u'teacher', u'teachers']:
service = croom.courses().teachers() service = croom.courses().teachers()
kwargs[u'userId'] = remove_id kwargs = {u'userId': remove_id}
elif participant_type in [u'student', u'students']: elif participant_type in [u'student', u'students']:
service = croom.courses().students() service = croom.courses().students()
kwargs[u'userId'] = remove_id kwargs = {u'userId': remove_id}
elif participant_type in [u'alias']: elif participant_type in [u'alias']:
service = croom.courses().aliases() service = croom.courses().aliases()
if remove_id[1] != u':': kwargs = {u'alias': addCourseIdScope(remove_id)}
remove_id = u'd:%s' % remove_id
kwargs[u'alias'] = remove_id
else: else:
print u'ERROR: %s is not a valid argument to "gam course ID delete"' % participant_type print u'ERROR: %s is not a valid argument to "gam course ID delete"' % participant_type
sys.exit(2) sys.exit(2)
callGAPI(service, u'delete', courseId=courseId, **kwargs) callGAPI(service, u'delete', courseId=courseId, **kwargs)
if courseId[:2] == u'd:': print u'Removed %s as a %s of course %s' % (removeCourseIdScope(remove_id), participant_type, removeCourseIdScope(courseId))
courseId = courseId[2:]
if remove_id[:2] == u'd:':
remove_id = remove_id[2:]
print u'Removed %s as a %s of course %s' % (remove_id, participant_type, courseId)
def doDelCourse(): def doDelCourse():
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
courseId = sys.argv[3] courseId = addCourseIdScope(sys.argv[3])
if not courseId.isdigit() and courseId[:2] != u'd:':
courseId = u'd:%s' % courseId
callGAPI(croom.courses(), u'delete', id=courseId) callGAPI(croom.courses(), u'delete', id=courseId)
print u'Deleted Course %s' % courseId print u'Deleted Course %s' % courseId
@ -1588,9 +1576,7 @@ def _getCourseStates(croom, value, courseStates):
def doUpdateCourse(): def doUpdateCourse():
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
courseId = sys.argv[3] courseId = addCourseIdScope(sys.argv[3])
if not courseId.isdigit() and courseId[:2] != u'd:':
courseId = u'd:%s' % courseId
body = {} body = {}
i = 4 i = 4
while i < len(sys.argv): while i < len(sys.argv):
@ -2293,9 +2279,7 @@ def doCreateCourse():
def doGetCourseInfo(): def doGetCourseInfo():
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
courseId = sys.argv[3] courseId = addCourseIdScope(sys.argv[3])
if not courseId.isdigit() and courseId[:2] != u'd:':
courseId = u'd:%s' % courseId
info = callGAPI(croom.courses(), u'get', id=courseId) info = callGAPI(croom.courses(), u'get', id=courseId)
info['ownerEmail'] = convertUIDtoEmailAddress(u'uid:%s' % info['ownerId']) info['ownerEmail'] = convertUIDtoEmailAddress(u'uid:%s' % info['ownerId'])
print_json(None, info) print_json(None, info)
@ -3192,7 +3176,7 @@ def doPrinterRegister():
cp = buildGAPIObject(u'cloudprint') cp = buildGAPIObject(u'cloudprint')
form_fields = {u'name': u'GAM', form_fields = {u'name': u'GAM',
u'proxy': u'GAM', u'proxy': u'GAM',
u'uuid': cp._http.request.credentials.id_token[u'sub'], u'uuid': _getValueFromOAuth(u'sub'),
u'manufacturer': gam_author, u'manufacturer': gam_author,
u'model': u'cp1', u'model': u'cp1',
u'gcp_version': u'2.0', u'gcp_version': u'2.0',
@ -3326,12 +3310,7 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity
if not act_as: if not act_as:
calendarId = normalizeCalendarId(calendarId) calendarId = normalizeCalendarId(calendarId)
act_as = calendarId act_as = calendarId
_, cal = buildCalendarGAPIObject(act_as) _, cal = buildCalendarDataGAPIObject(act_as)
try:
# Force service account token request. If we fail fall back to using admin for authentication
cal._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]))
except oauth2client.client.HttpAccessTokenRefreshError:
_, cal = buildCalendarGAPIObject(_getValueFromOAuth(u'email'))
body = {u'scope': {}} body = {u'scope': {}}
if role is not None: if role is not None:
body[u'role'] = role body[u'role'] = role
@ -11129,8 +11108,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
elif entity_type in [u'courseparticipants', u'teachers', u'students']: elif entity_type in [u'courseparticipants', u'teachers', u'students']:
croom = buildGAPIObject(u'classroom') croom = buildGAPIObject(u'classroom')
users = [] users = []
if not entity.isdigit() and entity[:2] != u'd:': entity = addCourseIdScope(entity)
entity = u'd:%s' % entity
if entity_type in [u'courseparticipants', u'teachers']: if entity_type in [u'courseparticipants', u'teachers']:
page_message = u'Got %%total_items%% teachers...' page_message = u'Got %%total_items%% teachers...'
teachers = callGAPIpages(croom.courses().teachers(), u'list', u'teachers', page_message=page_message, courseId=entity) teachers = callGAPIpages(croom.courses().teachers(), u'list', u'teachers', page_message=page_message, courseId=entity)
@ -11971,6 +11949,9 @@ def ProcessGAMCommand(args):
sys.exit(2) sys.exit(2)
sys.exit(0) sys.exit(0)
elif command == u'printer': elif command == u'printer':
if sys.argv[2].lower() == u'register':
doPrinterRegister()
sys.exit(0)
argument = sys.argv[3].lower() argument = sys.argv[3].lower()
if argument == u'showacl': if argument == u'showacl':
doPrinterShowACL() doPrinterShowACL()
@ -11978,8 +11959,6 @@ def ProcessGAMCommand(args):
doPrinterAddACL() doPrinterAddACL()
elif argument in [u'del', u'delete', u'remove']: elif argument in [u'del', u'delete', u'remove']:
doPrinterDelACL() doPrinterDelACL()
elif argument == u'register':
doPrinterRegister()
else: else:
print u'ERROR: %s is not a valid argument for "gam printer..."' % argument print u'ERROR: %s is not a valid argument for "gam printer..."' % argument
sys.exit(2) sys.exit(2)