def __init__(self, access_token): self.access_token = access_token self.api_base_uri = constant.Resources.MSGraph + 'v1.0' + '/' self.rest_api_service = RestApiService() auth_provider = AuthProvider() auth_provider.access_token(self.access_token) self.ms_graph_client = msgraph.GraphServiceClient( self.api_base_uri, auth_provider, msgraph.HttpProvider())
class AADGraphService(object): def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.AADGraph + tenant_id + '/' self.access_token = access_token self.rest_api_service = RestApiService() def get_service_principal(self): url = self.api_base_uri + "servicePrincipals?api-version=1.6&$filter=appId eq '%s'" % constant.client_id app_content = self.rest_api_service.get_json(url, self.access_token) return app_content['value'][0] def delete_service_principal(self, service_principal_id): version = '?api-version=1.6' url = self.api_base_uri + 'servicePrincipals/%s' % service_principal_id + version self.rest_api_service.delete(url, self.access_token) def add_app_role_assignments(self, service_principal_id, service_principal_id_name): url = self.api_base_uri + 'users?api-version=1.6&$expand=appRoleAssignments' users_content = self.rest_api_service.get_json(url, self.access_token) users = users_content['value'] count = 0 for user in users: if all(a['resourceId'] != service_principal_id for a in user['appRoleAssignments']): self._add_app_role_assignment(user, service_principal_id, service_principal_id_name) count = count + 1 return count def _add_app_role_assignment(self, user, service_principal_id, service_principal_id_name): app_role_assignment = { 'odata.type': 'Microsoft.DirectoryServices.AppRoleAssignment', 'principalDisplayName': user['displayName'], 'principalId': user['objectId'], 'principalType': 'User', 'resourceId': service_principal_id, 'resourceDisplayName': service_principal_id_name } post_url = self.api_base_uri + 'users/%s' % user['objectId'] + '/appRoleAssignments?api-version=1.6' self.rest_api_service.post_json(post_url, self.access_token, data=app_role_assignment)
def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.AADGraph + tenant_id + '/' self.access_token = access_token self.rest_api_service = RestApiService()
def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.MSGraph + '/' + constant.Resources.MSGraph_VERSION + '/' self.access_token = access_token self.rest_api_service = RestApiService() self.skip_token_re = re.compile('(?<=skiptoken=).*')
class EducationService(object): def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.MSGraph + '/' + constant.Resources.MSGraph_VERSION + '/' self.access_token = access_token self.rest_api_service = RestApiService() self.skip_token_re = re.compile('(?<=skiptoken=).*') def get_me(self): url = self.api_base_uri + 'education/me?$expand=schools,classes' return self.rest_api_service.get_object(url, self.access_token, model=EduUser) def get_schools(self): ''' Get all schools that exist in the Azure Active Directory tenant. ''' url = self.api_base_uri + 'education/schools' return self.rest_api_service.get_object_list(url, self.access_token, model=School) def get_school(self, school_id): ''' Get a school by using the object_id. ''' url = self.api_base_uri + 'education/schools/%s' % school_id return self.rest_api_service.get_object(url, self.access_token, model=School) def get_my_classes(self, school_id=None): ''' Get my classes within a school <param name="school_id">The school id.</param> ''' url = self.api_base_uri + 'education/me/classes?$expand=schools' classes = self.rest_api_service.get_object_list(url, self.access_token, model=Class) if school_id: classes = [ c for c in classes if any(s.id == school_id for s in c.schools) ] for c in classes: c.members = self.get_class_members(c.id) classes.sort(key=lambda c: c.code) return classes def get_classes(self, school_id, top=12, nextlink=''): ''' Get classes within a school <param name="school_id">The school id.</param> <param name="mysection_emails">All my section's email</param> <param name="top">Get record number from API</param> <param name="nextlink">Get skiptoken from nextlink</param> ''' skiptoken = self._get_skip_token(nextlink) url = self.api_base_uri + "education/schools/%s/classes?$expand=schools&$top=%s&skiptoken=%s" % ( school_id, top, skiptoken) return self.rest_api_service.get_object_list( url, self.access_token, model=Class, next_key='@odata.nextLink') def get_class(self, class_id): ''' Get a section by using the object_id. <param name="object_id">The Object ID of the section.</param> ''' url = self.api_base_uri + "education/classes/%s" % class_id return self.rest_api_service.get_object(url, self.access_token, model=Class) def get_class_members(self, class_id): ''' Get a class members by using the object_id. <param name="class_id">The Object ID of the section.</param> <param name="object_type">The members type.</param> ''' url = self.api_base_uri + 'education/classes/%s/members' % class_id return self.rest_api_service.get_object_list(url, self.access_token, model=EduUser) def get_teachers(self, school_id): ''' Get teachers within a school ''' url = self.api_base_uri + "users?$filter=extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_SchoolId eq '%s' and extension_fe2174665583431c953114ff7268b7b3_Education_ObjectType eq 'Teacher'" % school_id return self.rest_api_service.get_object_list(url, self.access_token, model=EduUser) def add_member(self, class_id, user_id): ''' Add a user to members of a class. Reference URL: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/group_post_members ''' url = self.api_base_uri + "groups/" + class_id + "/members/$ref" data = { '@odata.id': 'https://graph.microsoft.com/v1.0/directoryObjects/' + user_id } return self.rest_api_service.post_json(url, self.access_token, None, data) def add_owner(self, class_id, user_id): ''' Add a user to owner of a class. Reference URL: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/group_post_owners ''' url = self.api_base_uri + "groups/" + class_id + "/owners/$ref" data = { '@odata.id': 'https://graph.microsoft.com/v1.0/users/' + user_id } return self.rest_api_service.post_json(url, self.access_token, None, data) def get_assignments(self, class_id): ''' Get assignments of a class. ''' url = self.api_base_uri + 'education/classes/' + class_id + "/assignments" return self.rest_api_service.get_object_list(url, self.access_token, model=Assignment) def get_assignment(self, class_id, assignment_id): url = self.api_base_uri + 'education/classes/' + class_id + "/assignments/" + assignment_id return self.rest_api_service.get_object(url, self.access_token, model=Assignment) def add_assignment(self, class_id, name, dueDateTime): url = self.api_base_uri + 'education/classes/' + class_id + "/assignments" data = { "displayName": name, "status": "draft", "dueDateTime": dueDateTime, "allowStudentsToAddResourcesToSubmission": "true", "assignTo": { "@odata.type": "#microsoft.graph.educationAssignmentClassRecipient" } } return self.rest_api_service.post_json(url, self.access_token, None, data) def publish_assignment(self, class_id, assignment_id): url = self.api_base_uri + "education/classes/" + class_id + "/assignments/" + assignment_id + "/publish" return self.rest_api_service.post_json(url, self.access_token, None, None) def get_Assignment_Resource_Folder_URL(self, class_id, assignment_id): url = self.api_base_uri + "education/classes/" + class_id + "/assignments/" + assignment_id + "/GetResourcesFolderUrl" return self.rest_api_service.get_json(url, self.access_token) def get_Assignment_Resources(self, class_id, assignment_id): url = self.api_base_uri + "education/classes/" + class_id + "/assignments/" + assignment_id + "/resources" return self.rest_api_service.get_object_list(url, self.access_token, model=AssignmentResource) def get_Assignment_Submissions_By_User(self, class_id, assignment_id, user_id): url = self.api_base_uri + 'education/classes/' + class_id + '/assignments/' + assignment_id + '/submissions?$filter=submittedBy/user/id eq \'' + user_id + '\'' return self.rest_api_service.get_object_list(url, self.access_token, model=AssignmentResource) def get_Submission_Resources(self, class_id, assignment_id, user_id): url = self.api_base_uri + 'education/classes/' + class_id + '/assignments/' + assignment_id + '/submissions?$filter=submittedBy/user/id eq \'' + user_id + '\'' return self.rest_api_service.get_object_list(url, self.access_token, model=AssignmentResource) def get_Submissions(self, class_id, assignment_id): url = self.api_base_uri + 'education/classes/' + class_id + '/assignments/' + assignment_id + '/submissions' return self.rest_api_service.get_object_list(url, self.access_token, model=Submission) def get_Submission_Resources(self, class_id, assignment_id, submission_id): url = self.api_base_uri + 'education/classes/' + class_id + '/assignments/' + assignment_id + '/submissions/' + submission_id + '/resources' return self.rest_api_service.get_object_list( url, self.access_token, model=EducationAssignmentResource) def add_assignment_resources(self, class_id, assignment_id, fileName, resourceURL): url = self.api_base_uri + "/education/classes/" + class_id + "/assignments/" + assignment_id + "/resources" fileType = self.get_fileType(fileName) json = { "resource": { "displayName": fileName, "@odata.type": fileType, "file": { "odataid": resourceURL } } } self.rest_api_service.post_json(url, self.access_token, None, json) def add_Submission_Resource(self, class_id, assignment_id, fileName, resourceURL, submission_id): url = self.api_base_uri + "/education/classes/" + class_id + "/assignments/" + assignment_id + "/submissions/" + submission_id + "/resources" fileType = self.get_fileType(fileName) json = { "resource": { "displayName": fileName, "@odata.type": fileType, "file": { "odataid": resourceURL } } } self.rest_api_service.post_json(url, self.access_token, None, json) def get_fileType(self, fileName): defaultFileType = "#microsoft.graph.educationFileResource" if fileName.find(".docx") != -1: defaultFileType = "#microsoft.graph.educationWordResource" if fileName.find(".xlsx") != -1: defaultFileType = "#microsoft.graph.educationExcelResource" return defaultFileType def uploadFileToOneDrive(self, ids, file): url = "https://graph.microsoft.com/v1.0/drives/" + ids[ 0] + "/items/" + ids[1] + ":/" + file.name + ":/content" return self.rest_api_service.put_file(url, self.access_token, file) def _get_skip_token(self, nextlink): if nextlink: matches = self.skip_token_re.findall(nextlink) if matches: return matches[0] return ''
class MSGraphService(object): def __init__(self, access_token): self.access_token = access_token self.api_base_uri = constant.Resources.MSGraph + 'v1.0' + '/' self.rest_api_service = RestApiService() auth_provider = AuthProvider() auth_provider.access_token(self.access_token) self.ms_graph_client = msgraph.GraphServiceClient( self.api_base_uri, auth_provider, msgraph.HttpProvider()) def get_o365_user(self, tenant_id): me = self._get_me().to_dict() org = self._get_organization(tenant_id) id = me['id'] first_name = me['givenName'] last_name = me['surname'] display_name = me['displayName'] email = me['mail'] if not email: email = me['userPrincipalName'] tenant_name = org['displayName'] roles = self._get_roles(id) photo = '/Photo/UserPhoto/' + id return O365User(id, email, first_name, last_name, display_name, tenant_id, tenant_name, roles, photo) def get_photo(self, object_id): url = self.api_base_uri + 'users/%s/photo/$value' % object_id try: return self.rest_api_service.get_img(url, self.access_token) except: return None def get_documents(self, object_id): url = self.api_base_uri + 'groups/%s/drive/root/children' % object_id return self.rest_api_service.get_object_list(url, self.access_token, model=Document) def get_documents_root(self, object_id): url = self.api_base_uri + 'groups/%s/drive/root' % object_id document = self.rest_api_service.get_object(url, self.access_token, model=Document) return document.web_url def get_conversations(self, object_id): url = self.api_base_uri + 'groups/%s/conversations' % object_id return self.rest_api_service.get_object_list(url, self.access_token, model=Conversation) def get_conversations_url(self, conversation_id, section_email): return 'https://outlook.office.com/owa/?path=/group/%s/mail&exsvurl=1&ispopout=0&ConvID=%s' % ( section_email, conversation_id, ) def get_conversations_root(self, section_email): return 'https://outlook.office.com/owa/?path=/group/%s/mail&exsvurl=1&ispopout=0' % section_email def _get_roles(self, user_id): roles = [] # check if the user is an admin directory_roles = self._get_directory_roles() admin_role = next( r for r in directory_roles if r.display_name == constant.company_admin_role_name) if admin_role: members = admin_role.to_dict()['members'] if any(m for m in members if m['id'] == user_id): roles.append(constant.Roles.Admin) # check if the user is a faculty or a student assigned_licenses = self._get_assigned_licenses() for license in assigned_licenses: license_id = license['skuId'] if license_id == constant.O365ProductLicenses.Faculty or license_id == constant.O365ProductLicenses.FacultyPro: roles.append(constant.Roles.Faculty) if license_id == constant.O365ProductLicenses.Student or license_id == constant.O365ProductLicenses.StudentPro: roles.append(constant.Roles.Student) return roles def _get_me(self): return self.ms_graph_client.me.get() def _get_assigned_licenses(self): url = self.api_base_uri + 'me/assignedLicenses' return self.rest_api_service.get_json(url, self.access_token)['value'] def _get_organization(self, tenant_id): url = self.api_base_uri + 'organization/' + tenant_id return self.rest_api_service.get_json(url, self.access_token) def _get_directory_roles(self): expand_members = msgraph.options.QueryOption('$expand', 'members') return self.ms_graph_client.directory_roles.request( options=[expand_members]).get()
class AADGraphService(object): def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.AADGraph + '/' + tenant_id + '/' self.access_token = access_token self.skip_token_re = re.compile('(?<=skiptoken=).*') self.rest_api_service = RestApiService() def get_service_principal(self): url = self.api_base_uri + "servicePrincipals?api-version=1.6&$filter=appId eq '%s'" % constant.client_id app_content = self.rest_api_service.get_json(url, self.access_token) return next(iter(app_content['value']), None) def delete_service_principal(self, service_principal_id): version = '?api-version=1.6' url = self.api_base_uri + 'servicePrincipals/%s' % service_principal_id + version self.rest_api_service.delete(url, self.access_token) def add_app_role_assignments(self, service_principal_id, service_principal_id_name): count = 0 url = self.api_base_uri + 'users?api-version=1.6&$expand=appRoleAssignments' skip_token = None while True: url2 = url + '&$skiptoken=' + skip_token if skip_token else url users_content = self.rest_api_service.get_json( url2, self.access_token) users = users_content['value'] skip_token = self._get_skip_token( users_content.get('odata.nextLink')) for user in users: if all(a['resourceId'] != service_principal_id for a in user['appRoleAssignments']): try: self._add_app_role_assignment( user, service_principal_id, service_principal_id_name) count = count + 1 except: pass if skip_token == None: break return count def _add_app_role_assignment(self, user, service_principal_id, service_principal_id_name): app_role_assignment = { 'odata.type': 'Microsoft.DirectoryServices.AppRoleAssignment', 'principalDisplayName': user['displayName'], 'principalId': user['objectId'], 'principalType': 'User', 'resourceId': service_principal_id, 'resourceDisplayName': service_principal_id_name } post_url = self.api_base_uri + 'users/%s' % user[ 'objectId'] + '/appRoleAssignments?api-version=1.6' self.rest_api_service.post_json(post_url, self.access_token, data=app_role_assignment) def _get_skip_token(self, nextlink): if nextlink: matches = self.skip_token_re.findall(nextlink) if matches: return matches[0] return None
class EducationService(object): def __init__(self, tenant_id, access_token): self.api_base_uri = constant.Resources.MSGraph + constant.Resources.MSGraph_VERSION + '/' self.access_token = access_token self.rest_api_service = RestApiService() self.skip_token_re = re.compile('\$skiptoken=.*') def get_my_school_id(self): url = self.api_base_uri + 'me' user_content = self.rest_api_service.get_json(url, self.access_token) school_id = user_content.get( 'extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_SchoolId', '') return school_id def get_school_user_id(self): url = self.api_base_uri + 'me' user_content = self.rest_api_service.get_json(url, self.access_token) sid = user_content.get( 'extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_StudentId', '') tid = user_content.get( 'extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_TeacherId', '') if sid: return sid elif tid: return tid def get_schools(self): ''' Get all schools that exist in the Azure Active Directory tenant. ''' url = self.api_base_uri + 'administrativeUnits' return self.rest_api_service.get_object_list(url, self.access_token, model=School) def get_school(self, object_id): ''' Get a school by using the object_id. <param name="object_id">The Object ID of the school administrative unit in Azure Active Directory.</param> ''' url = self.api_base_uri + 'administrativeUnits/%s' % object_id return self.rest_api_service.get_object(url, self.access_token, model=School) def get_section_members(self, section_object_id): ''' Get a section members by using the object_id. <param name="section_object_id">The Object ID of the section.</param> <param name="object_type">The members type.</param> ''' url = self.api_base_uri + 'groups/%s?$expand=members' % section_object_id return self.rest_api_service.get_object_list(url, self.access_token, key='members', model=EduUser) def get_my_sections(self, school_id): ''' Get my sections within a school <param name="school_id">The school id.</param> ''' url = self.api_base_uri + 'me/memberOf' section_list = self.rest_api_service.get_object_list(url, self.access_token, model=Section) mysection_list = [ s for s in section_list if s.education_object_type == 'Section' and s.school_id == school_id ] for section in mysection_list: section.members = self.get_section_members(section.id) mysection_list.sort(key=lambda d: d.combined_course_number) return mysection_list def get_sections(self, school_id, top=12, nextlink=''): ''' Get sections within a school <param name="school_id">The school id.</param> <param name="mysection_emails">All my section's email</param> <param name="top">Get record number from API</param> <param name="nextlink">Get skiptoken from nextlink</param> ''' skiptoken = self._get_skip_token(nextlink) url = self.api_base_uri + "groups?$filter=extension_fe2174665583431c953114ff7268b7b3_Education_ObjectType eq 'Section' and extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_SchoolId eq '%s'&$top=%s%s" % ( school_id, top, skiptoken) return self.rest_api_service.get_object_list( url, self.access_token, model=Section, next_key='@odata.nextLink') def get_section(self, object_id): ''' Get a section by using the object_id. <param name="object_id">The Object ID of the section.</param> ''' url = self.api_base_uri + 'groups/%s' % object_id return self.rest_api_service.get_object(url, self.access_token, model=Section) def get_members(self, object_id, top=12, nextlink=''): ''' Get members within a school <param name="object_id">The Object ID of the school.</param> <param name="top">Get record number from API</param> <param name="nextlink">Get skiptoken from nextlink</param> ''' skiptoken = self._get_skip_token(nextlink) url = self.api_base_uri + 'administrativeUnits/%s/members?$top=%s%s' % ( object_id, top, skiptoken) return self.rest_api_service.get_object_list( url, self.access_token, model=EduUser, next_key='@odata.nextLink') def get_students(self, school_id, top=12, nextlink=''): ''' Get students within a school <param name="school_id">The school id.</param> <param name="top">Get record number from API</param> <param name="nextlink">Get skiptoken from nextlink</param> ''' skiptoken = self._get_skip_token(nextlink) url = self.api_base_uri + "users?$filter=extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_SchoolId eq '%s' and extension_fe2174665583431c953114ff7268b7b3_Education_ObjectType eq 'Student'&$top=%s%s" % ( school_id, top, skiptoken) return self.rest_api_service.get_object_list( url, self.access_token, model=EduUser, next_key='@odata.nextLink') def get_teachers(self, school_id, top=12, nextlink=''): ''' Get teachers within a school <param name="school_id">The school id.</param> <param name="top">Get record number from API</param> <param name="nextlink">Get skiptoken from nextlink</param> ''' skiptoken = self._get_skip_token(nextlink) url = self.api_base_uri + "users?$filter=extension_fe2174665583431c953114ff7268b7b3_Education_SyncSource_SchoolId eq '%s' and extension_fe2174665583431c953114ff7268b7b3_Education_ObjectType eq 'Teacher'&$top=%s%s" % ( school_id, top, skiptoken) return self.rest_api_service.get_object_list( url, self.access_token, model=EduUser, next_key='@odata.nextLink') def _get_skip_token(self, nextlink): if nextlink and nextlink.find('skiptoken') != -1: link_skiptoken = self.skip_token_re.findall(nextlink)[0] return '&%s' % link_skiptoken return ''