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))
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']