def delete_current_user_app_registrations(contains: str) -> None: if not contains: raise Exception("Contains string must be set to a valid string") cred = AzCliMsGraphAuth() client = GraphClient(credential=cred) result = client.get("/me") result = client.get(f'/users/{result.json()["id"]}/ownedObjects') my_apps = [] for x in result.json()["value"]: if (x["@odata.type"] == "#microsoft.graph.application" and contains in x["displayName"]): my_apps.append((x["displayName"], x["id"])) for (name, id) in my_apps: print("Deleting: %s (%s)" % (name, id)) result = client.delete(f"/applications/{id}") if not result.ok: print("Failed to delete: %s (%s) due to : %s" % (name, id, result.reason)) result = client.get(f"/directory/deletedItems/{id}") if result.ok: deleted_app = result.json() if deleted_app["id"] == id: result = client.delete("/directory/deleteditems/%s" % id) if result.ok: print("Permanently deleted: %s (%s)" % (name, id)) else: print("Failed to permanently delete: %s (%s) due to : %s" % (name, id, result.reason))
def test_does_not_build_graph_urls_for_full_urls(): """ Test that the graph client builds full urls if supplied with partial """ other_url = 'https://microsoft.com/' responses.add(responses.GET, other_url, status=200) credential = _CustomTokenCredential() client = GraphClient(credential=credential) client.get(other_url, headers={}) request_url = responses.calls[0].request.url assert other_url == request_url
def test_graph_client_builds_graph_urls(): """ Test that the graph client builds full urls if supplied with partial """ credential = _CustomTokenCredential() client = GraphClient(credential=credential) graph_url = client.graph_session.base_url + '/me' responses.add(responses.GET, graph_url, status=200) client.get('/me', headers={}) assert graph_url == responses.calls[0].request.url
class AzUsers(object): def __init__(self, credential): self.graph_client = GraphClient(credential=credential) def get_azure_user_id(self, netid): username = '******'.format(netid, settings.USERNAME_EMAIL_HOST) response = self.graph_client.get('/users/' + username) response.raise_for_status() return response.json()["id"]
def test_graph_client_with_custom_settings(): """ Test that the graph client works with user provided configuration """ credential = _CustomTokenCredential() client = GraphClient(api_version=APIVersion.beta, credential=credential) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me' ) assert response.status_code == 200
def test_graph_client_with_default_middleware(): """ Test that a graph client uses default middleware if none are provided """ credential = _CustomTokenCredential() client = GraphClient(credential=credential) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me' ) assert response.status_code == 200
def test_graph_client_with_user_provided_session(): """ Test that the graph client works with a user provided session object """ session = Session() credential = _CustomTokenCredential() client = GraphClient(session=session, credential=credential) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me' ) assert response.status_code == 200
def test_graph_client_adds_context_to_request(): """ Test the graph client adds a context object to a request """ credential = _CustomTokenCredential() scopes = ['User.Read.All'] client = GraphClient(credential=credential) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me', scopes=scopes ) assert response.status_code == 200 assert hasattr(response.request, 'context')
def test_graph_client_with_custom_middleware(): """ Test client factory works with user provided middleware """ credential = _CustomTokenCredential() middleware = [ AuthorizationHandler(credential), ] client = GraphClient(middleware=middleware) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me' ) assert response.status_code == 200
def test_graph_client_picks_options_from_kwargs(): """ Test the graph client picks middleware options from kwargs and sets them in the context """ credential = _CustomTokenCredential() scopes = ['User.Read.All'] client = GraphClient(credential=credential) response = client.get( 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=https://graph.microsoft.com/v1.0/me', scopes=scopes ) assert response.status_code == 200 assert 'scopes' in response.request.context.middleware_control.keys() assert response.request.context.middleware_control['scopes'] == scopes
def client_with_custom_middleware(): """Sample client with a custom middleware chain""" middleware = [ CustomAuthorizationHandler(), MyCustomMiddleware(), ] my_client = GraphClient(credential=browser_credential, middleware=middleware) result = my_client.get( 'https://graph.microsoft.com/v1.0/users', params={ '$select': 'displayName', '$top': '10' }, ) pprint(result.json())
def client_with_custom_settings_sample(): """ Sample client that makes requests against the beta api on a specified cloud endpoint """ my_client = GraphClient( credential=browser_credential, api_version=APIVersion.beta, cloud=NationalClouds.Germany, ) result = my_client.get( '/users', params={ '$select': 'displayName', '$top': '10' }, ) pprint(result.json())
def client_with_custom_session_sample(): """Sample client with a custom Session object""" session = Session() my_client = GraphClient(credential=browser_credential, session=session) result = my_client.get('/me') pprint(result.json())
class MSGraphConnection(MailboxConnection): def __init__(self, auth_method: str, mailbox: str, client_id: str, client_secret: str, username: str, password: str, tenant_id: str, token_file: str): token_path = Path(token_file) credential = _generate_credential(auth_method, client_id=client_id, client_secret=client_secret, username=username, password=password, tenant_id=tenant_id, token_path=token_path) scopes = ['Mail.ReadWrite'] # Detect if mailbox is shared if mailbox and username != mailbox: scopes = ['Mail.ReadWrite.Shared'] if not isinstance(credential, ClientSecretCredential): auth_record = credential.authenticate(scopes=scopes) _cache_auth_record(auth_record, token_path) self._client = GraphClient(credential=credential) self.mailbox_name = mailbox def create_folder(self, folder_name: str): sub_url = '' path_parts = folder_name.split('/') if len(path_parts) > 1: # Folder is a subFolder parent_folder_id = None for folder in path_parts[:-1]: parent_folder_id = self._find_folder_id_with_parent( folder, parent_folder_id) sub_url = f'/{parent_folder_id}/childFolders' folder_name = path_parts[-1] request_body = {'displayName': folder_name} request_url = f'/users/{self.mailbox_name}/mailFolders{sub_url}' resp = self._client.post(request_url, json=request_body) if resp.status_code == 409: logger.debug(f'Folder {folder_name} already exists, ' f'skipping creation') elif resp.status_code == 201: logger.debug(f'Created folder {folder_name}') else: logger.warning(f'Unknown response ' f'{resp.status_code} {resp.json()}') def fetch_messages(self, folder_name: str, **kwargs) -> List[str]: """ Returns a list of message UIDs in the specified folder """ folder_id = self._find_folder_id_from_folder_path(folder_name) batch_size = kwargs.get('batch_size', 10) url = f'/users/{self.mailbox_name}/mailFolders/' \ f'{folder_id}/messages?$select=id&$top={batch_size}' result = self._client.get(url) emails = result.json()['value'] return [email['id'] for email in emails] def mark_message_read(self, message_id: str): """Marks a message as read""" url = f'/users/{self.mailbox_name}/messages/{message_id}' resp = self._client.patch(url, json={"isRead": "true"}) if resp.status_code != 200: raise RuntimeWarning(f"Failed to mark message read" f"{resp.status_code}: {resp.json()}") def fetch_message(self, message_id: str): url = f'/users/{self.mailbox_name}/messages/{message_id}/$value' result = self._client.get(url) self.mark_message_read(message_id) return result.text def delete_message(self, message_id: str): url = f'/users/{self.mailbox_name}/messages/{message_id}' resp = self._client.delete(url) if resp.status_code != 204: raise RuntimeWarning(f"Failed to delete message " f"{resp.status_code}: {resp.json()}") def move_message(self, message_id: str, folder_name: str): folder_id = self._find_folder_id_from_folder_path(folder_name) request_body = {'destinationId': folder_id} url = f'/users/{self.mailbox_name}/messages/{message_id}/move' resp = self._client.post(url, json=request_body) if resp.status_code != 201: raise RuntimeWarning(f"Failed to move message " f"{resp.status_code}: {resp.json()}") def keepalive(self): # Not needed pass def watch(self, check_callback, check_timeout): """ Checks the mailbox for new messages every n seconds""" while True: sleep(check_timeout) check_callback(self) @lru_cache(maxsize=10) def _find_folder_id_from_folder_path(self, folder_name: str) -> str: path_parts = folder_name.split('/') parent_folder_id = None if len(path_parts) > 1: for folder in path_parts[:-1]: folder_id = self._find_folder_id_with_parent( folder, parent_folder_id) parent_folder_id = folder_id return self._find_folder_id_with_parent(path_parts[-1], parent_folder_id) else: return self._find_folder_id_with_parent(folder_name, None) def _find_folder_id_with_parent(self, folder_name: str, parent_folder_id: Optional[str]): sub_url = '' if parent_folder_id is not None: sub_url = f'/{parent_folder_id}/childFolders' url = f'/users/{self.mailbox_name}/mailFolders{sub_url}' folders_resp = self._client.get(url) folders = folders_resp.json()['value'] matched_folders = [ folder for folder in folders if folder['displayName'] == folder_name ] if len(matched_folders) == 0: raise RuntimeError(f"folder {folder_name} not found") selected_folder = matched_folders[0] return selected_folder['id']