diff --git a/slack_sdk/oauth/installation_store/amazon_s3/__init__.py b/slack_sdk/oauth/installation_store/amazon_s3/__init__.py index 9bec01731..79dbccab0 100644 --- a/slack_sdk/oauth/installation_store/amazon_s3/__init__.py +++ b/slack_sdk/oauth/installation_store/amazon_s3/__init__.py @@ -206,3 +206,76 @@ def find_installation( message = f"Failed to find an installation data for enterprise: {e_id}, team: {t_id}: {e}" self.logger.warning(message) return None + + async def async_delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + return self.delete_bot( + enterprise_id=enterprise_id, + team_id=team_id, + ) + + def delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + none = "none" + e_id = enterprise_id or none + t_id = team_id or none + workspace_path = f"{self.client_id}/{e_id}-{t_id}" + objects = self.s3_client.list_objects( + Bucket=self.bucket_name, + Prefix=f"{workspace_path}/bot-", + ) + for content in objects.get("Contents", []): + key = content.get("Key") + if key is not None: + self.logger.info(f"Going to delete bot installation ({key})") + try: + self.s3_client.delete_object( + Bucket=self.bucket_name, + Key=content.get("Key"), + ) + except Exception as e: # skipcq: PYL-W0703 + message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" + self.logger.warning(message) + + async def async_delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + return self.delete_installation( + enterprise_id=enterprise_id, + team_id=team_id, + user_id=user_id, + ) + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + none = "none" + e_id = enterprise_id or none + t_id = team_id or none + workspace_path = f"{self.client_id}/{e_id}-{t_id}" + objects = self.s3_client.list_objects( + Bucket=self.bucket_name, + Prefix=f"{workspace_path}/installer-{user_id or ''}", + ) + for content in objects.get("Contents", []): + key = content.get("Key") + if key is not None: + self.logger.info(f"Going to delete installation ({key})") + try: + self.s3_client.delete_object( + Bucket=self.bucket_name, + Key=content.get("Key"), + ) + except Exception as e: # skipcq: PYL-W0703 + message = f"Failed to find bot installation data for enterprise: {e_id}, team: {t_id}: {e}" + self.logger.warning(message) diff --git a/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py b/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py index 2f89134a5..0fff80f84 100644 --- a/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py +++ b/slack_sdk/oauth/installation_store/async_cacheable_installation_store.py @@ -38,7 +38,7 @@ async def async_find_bot( ) -> Optional[Bot]: if is_enterprise_install or team_id is None: team_id = "" - key = f"{enterprise_id}-{team_id}" + key = f"{enterprise_id or ''}-{team_id or ''}" if key in self.cached_bots: return self.cached_bots[key] bot = await self.underlying.async_find_bot( @@ -60,7 +60,7 @@ async def async_find_installation( ) -> Optional[Installation]: if is_enterprise_install or team_id is None: team_id = "" - key = f"{enterprise_id}-{team_id}-{user_id}" + key = f"{enterprise_id or ''}-{team_id or ''}-{user_id or ''}" if key in self.cached_installations: return self.cached_installations[key] installation = await self.underlying.async_find_installation( @@ -72,3 +72,49 @@ async def async_find_installation( if installation: self.cached_installations[key] = installation return installation + + async def async_delete_bot( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ) -> None: + await self.underlying.async_delete_bot( + enterprise_id=enterprise_id, + team_id=team_id, + ) + key = f"{enterprise_id or ''}-{team_id or ''}" + self.cached_bots.pop(key) + + async def async_delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + await self.underlying.async_delete_installation( + enterprise_id=enterprise_id, + team_id=team_id, + user_id=user_id, + ) + key = f"{enterprise_id or ''}-{team_id or ''}={user_id or ''}" + self.cached_installations.pop(key) + + async def async_delete_all( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ): + await self.underlying.async_delete_all( + enterprise_id=enterprise_id, + team_id=team_id, + ) + key_prefix = f"{enterprise_id or ''}-{team_id or ''}" + for key in self.cached_bots.keys(): + if key.startswith(key_prefix): + self.cached_bots.pop(key) + for key in self.cached_installations.keys(): + if key.startswith(key_prefix): + self.cached_installations.pop(key) diff --git a/slack_sdk/oauth/installation_store/async_installation_store.py b/slack_sdk/oauth/installation_store/async_installation_store.py index a19af86a2..684965f92 100644 --- a/slack_sdk/oauth/installation_store/async_installation_store.py +++ b/slack_sdk/oauth/installation_store/async_installation_store.py @@ -6,11 +6,33 @@ class AsyncInstallationStore: + """The installation store interface for asyncio-based apps. + + The minimum required methods are: + + * async_save(installation) + * async_find_installation(enterprise_id, team_id, user_id, is_enterprise_install) + + If you would like to properly handle app uninstallations and token revocations, + the following methods should be implemented. + + * async_delete_installation(enterprise_id, team_id, user_id) + * async_delete_all(enterprise_id, team_id) + + If your app needs only bot scope installations, the simpler way to implement would be: + + * async_save(installation) + * async_find_bot(enterprise_id, team_id, is_enterprise_install) + * async_delete_bot(enterprise_id, team_id) + * async_delete_all(enterprise_id, team_id) + """ + @property def logger(self) -> Logger: raise NotImplementedError() async def async_save(self, installation: Installation): + """Saves a new installation data""" raise NotImplementedError() async def async_find_bot( @@ -20,6 +42,7 @@ async def async_find_bot( team_id: Optional[str], is_enterprise_install: Optional[bool] = False, ) -> Optional[Bot]: + """Finds a bot scope installation per workspace / org""" raise NotImplementedError() async def async_find_installation( @@ -30,4 +53,38 @@ async def async_find_installation( user_id: Optional[str] = None, is_enterprise_install: Optional[bool] = False, ) -> Optional[Installation]: + """Finds a relevant installation for the given IDs. + If the user_id is absent, this method may return the latest installation in the workspace / org. + """ + raise NotImplementedError() + + async def async_delete_bot( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ) -> None: + """Deletes a bot scope installation per workspace / org""" raise NotImplementedError() + + async def async_delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + """Deletes an installation that matches the given IDs""" + raise NotImplementedError() + + async def async_delete_all( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ): + """Deletes all installation data for the given workspace / org""" + await self.async_delete_bot(enterprise_id=enterprise_id, team_id=team_id) + await self.async_delete_installation( + enterprise_id=enterprise_id, team_id=team_id + ) diff --git a/slack_sdk/oauth/installation_store/cacheable_installation_store.py b/slack_sdk/oauth/installation_store/cacheable_installation_store.py index 67bee6cba..aff4b7a27 100644 --- a/slack_sdk/oauth/installation_store/cacheable_installation_store.py +++ b/slack_sdk/oauth/installation_store/cacheable_installation_store.py @@ -36,7 +36,7 @@ def find_bot( ) -> Optional[Bot]: if is_enterprise_install or team_id is None: team_id = "" - key = f"{enterprise_id}-{team_id}" + key = f"{enterprise_id or ''}-{team_id or ''}" if key in self.cached_bots: return self.cached_bots[key] bot = self.underlying.find_bot( @@ -58,7 +58,7 @@ def find_installation( ) -> Optional[Installation]: if is_enterprise_install or team_id is None: team_id = "" - key = f"{enterprise_id}-{team_id}={user_id}" + key = f"{enterprise_id or ''}-{team_id or ''}={user_id or ''}" if key in self.cached_installations: return self.cached_installations[key] installation = self.underlying.find_installation( @@ -70,3 +70,49 @@ def find_installation( if installation: self.cached_installations[key] = installation return installation + + def delete_bot( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ) -> None: + self.underlying.delete_bot( + enterprise_id=enterprise_id, + team_id=team_id, + ) + key = f"{enterprise_id or ''}-{team_id or ''}" + self.cached_bots.pop(key) + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + self.underlying.delete_installation( + enterprise_id=enterprise_id, + team_id=team_id, + user_id=user_id, + ) + key = f"{enterprise_id or ''}-{team_id or ''}={user_id or ''}" + self.cached_installations.pop(key) + + def delete_all( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ): + self.underlying.delete_all( + enterprise_id=enterprise_id, + team_id=team_id, + ) + key_prefix = f"{enterprise_id or ''}-{team_id or ''}" + for key in self.cached_bots.keys(): + if key.startswith(key_prefix): + self.cached_bots.pop(key) + for key in self.cached_installations.keys(): + if key.startswith(key_prefix): + self.cached_installations.pop(key) diff --git a/slack_sdk/oauth/installation_store/file/__init__.py b/slack_sdk/oauth/installation_store/file/__init__.py index f51f46ada..5af5e8ad1 100644 --- a/slack_sdk/oauth/installation_store/file/__init__.py +++ b/slack_sdk/oauth/installation_store/file/__init__.py @@ -1,5 +1,7 @@ +import glob import json import logging +import os from logging import Logger from pathlib import Path from typing import Optional, Union @@ -159,6 +161,55 @@ def find_installation( self.logger.warning(message) return None + async def async_delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + return self.delete_bot(enterprise_id=enterprise_id, team_id=team_id) + + def delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + none = "none" + e_id = enterprise_id or none + t_id = team_id or none + filepath_glob = f"{self.base_dir}/{e_id}-{t_id}/bot-*" + self._delete_by_glob(e_id, t_id, filepath_glob) + + async def async_delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + return self.delete_installation( + enterprise_id=enterprise_id, team_id=team_id, user_id=user_id + ) + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + none = "none" + e_id = enterprise_id or none + t_id = team_id or none + if user_id is not None: + filepath_glob = f"{self.base_dir}/{e_id}-{t_id}/installer-{user_id}-*" + else: + filepath_glob = f"{self.base_dir}/{e_id}-{t_id}/installer-*" + self._delete_by_glob(e_id, t_id, filepath_glob) + + def _delete_by_glob(self, e_id: str, t_id: str, filepath_glob: str): + for filepath in glob.glob(filepath_glob): + try: + os.remove(filepath) + except FileNotFoundError as e: + message = f"Failed to delete installation data for enterprise: {e_id}, team: {t_id}: {e}" + self.logger.warning(message) + @staticmethod def _mkdir(path: Union[str, Path]): if isinstance(path, str): diff --git a/slack_sdk/oauth/installation_store/installation_store.py b/slack_sdk/oauth/installation_store/installation_store.py index 6dd4211b3..a9abc1ccb 100644 --- a/slack_sdk/oauth/installation_store/installation_store.py +++ b/slack_sdk/oauth/installation_store/installation_store.py @@ -10,11 +10,33 @@ class InstallationStore: + """The installation store interface. + + The minimum required methods are: + + * save(installation) + * find_installation(enterprise_id, team_id, user_id, is_enterprise_install) + + If you would like to properly handle app uninstallations and token revocations, + the following methods should be implemented. + + * delete_installation(enterprise_id, team_id, user_id) + * delete_all(enterprise_id, team_id) + + If your app needs only bot scope installations, the simpler way to implement would be: + + * save(installation) + * find_bot(enterprise_id, team_id, is_enterprise_install) + * delete_bot(enterprise_id, team_id) + * delete_all(enterprise_id, team_id) + """ + @property def logger(self) -> Logger: raise NotImplementedError() def save(self, installation: Installation): + """Saves a new installation data""" raise NotImplementedError() def find_bot( @@ -24,6 +46,7 @@ def find_bot( team_id: Optional[str], is_enterprise_install: Optional[bool] = False, ) -> Optional[Bot]: + """Finds a bot scope installation per workspace / org""" raise NotImplementedError() def find_installation( @@ -34,4 +57,36 @@ def find_installation( user_id: Optional[str] = None, is_enterprise_install: Optional[bool] = False, ) -> Optional[Installation]: + """Finds a relevant installation for the given IDs. + If the user_id is absent, this method may return the latest installation in the workspace / org. + """ + raise NotImplementedError() + + def delete_bot( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ) -> None: + """Deletes a bot scope installation per workspace / org""" raise NotImplementedError() + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + """Deletes an installation that matches the given IDs""" + raise NotImplementedError() + + def delete_all( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + ): + """Deletes all installation data for the given workspace / org""" + self.delete_bot(enterprise_id=enterprise_id, team_id=team_id) + self.delete_installation(enterprise_id=enterprise_id, team_id=team_id) diff --git a/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py b/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py index d4d9a2cc1..554ba4fd1 100644 --- a/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py +++ b/slack_sdk/oauth/installation_store/sqlalchemy/__init__.py @@ -232,3 +232,48 @@ def find_installation( installed_at=row["installed_at"], ) return None + + def delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + table = self.bots + c = table.c + with self.engine.begin() as conn: + deletion = table.delete().where( + and_( + c.client_id == self.client_id, + c.enterprise_id == enterprise_id, + c.team_id == team_id, + ) + ) + conn.execute(deletion) + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + table = self.installations + c = table.c + with self.engine.begin() as conn: + if user_id is not None: + deletion = table.delete().where( + and_( + c.client_id == self.client_id, + c.enterprise_id == enterprise_id, + c.team_id == team_id, + c.user_id == user_id, + ) + ) + conn.execute(deletion) + else: + deletion = table.delete().where( + and_( + c.client_id == self.client_id, + c.enterprise_id == enterprise_id, + c.team_id == team_id, + ) + ) + conn.execute(deletion) diff --git a/slack_sdk/oauth/installation_store/sqlite3/__init__.py b/slack_sdk/oauth/installation_store/sqlite3/__init__.py index db2669c4b..42f915528 100644 --- a/slack_sdk/oauth/installation_store/sqlite3/__init__.py +++ b/slack_sdk/oauth/installation_store/sqlite3/__init__.py @@ -456,3 +456,73 @@ def find_installation( message = f"Failed to find an installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" self.logger.warning(message) return None + + def delete_bot( + self, *, enterprise_id: Optional[str], team_id: Optional[str] + ) -> None: + try: + with self.connect() as conn: + conn.execute( + """ + delete + from + slack_bots + where + client_id = ? + and + enterprise_id = ? + and + team_id = ? + """, + [self.client_id, enterprise_id or "", team_id or ""], + ) + conn.commit() + except Exception as e: # skipcq: PYL-W0703 + message = f"Failed to delete bot installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" + self.logger.warning(message) + + def delete_installation( + self, + *, + enterprise_id: Optional[str], + team_id: Optional[str], + user_id: Optional[str] = None, + ) -> None: + try: + with self.connect() as conn: + if user_id is None: + conn.execute( + """ + delete + from + slack_installations + where + client_id = ? + and + enterprise_id = ? + and + team_id = ? + """, + [self.client_id, enterprise_id or "", team_id], + ) + else: + conn.execute( + """ + delete + from + slack_installations + where + client_id = ? + and + enterprise_id = ? + and + team_id = ? + and + user_id = ? + """, + [self.client_id, enterprise_id or "", team_id, user_id], + ) + conn.commit() + except Exception as e: # skipcq: PYL-W0703 + message = f"Failed to delete installation data for enterprise: {enterprise_id}, team: {team_id}: {e}" + self.logger.warning(message) diff --git a/tests/slack_sdk/oauth/installation_store/test_file.py b/tests/slack_sdk/oauth/installation_store/test_file.py index cd5e597ab..da110fa0b 100644 --- a/tests/slack_sdk/oauth/installation_store/test_file.py +++ b/tests/slack_sdk/oauth/installation_store/test_file.py @@ -28,6 +28,7 @@ def test_save_and_find(self): ) store.save(installation) + # find bots bot = store.find_bot(enterprise_id="E111", team_id="T111") self.assertIsNotNone(bot) bot = store.find_bot(enterprise_id="E111", team_id="T222") @@ -35,6 +36,12 @@ def test_save_and_find(self): bot = store.find_bot(enterprise_id=None, team_id="T111") self.assertIsNone(bot) + # delete bots + store.delete_bot(enterprise_id="E111", team_id="T222") + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + + # find installations i = store.find_installation(enterprise_id="E111", team_id="T111") self.assertIsNotNone(i) i = store.find_installation(enterprise_id="E111", team_id="T222") @@ -55,6 +62,32 @@ def test_save_and_find(self): ) self.assertIsNone(i) + # delete installations + store.delete_installation(enterprise_id="E111", team_id="T111", user_id="U111") + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNotNone(i) + + store.delete_installation(enterprise_id="E111", team_id="T111") + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id="T111") + + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + def test_org_installation(self): store = FileInstallationStore(client_id="111.222") installation = Installation( @@ -69,6 +102,7 @@ def test_org_installation(self): ) store.save(installation) + # find bots bot = store.find_bot(enterprise_id="EO111", team_id=None) self.assertIsNotNone(bot) bot = store.find_bot( @@ -80,6 +114,16 @@ def test_org_installation(self): bot = store.find_bot(enterprise_id=None, team_id="TO111") self.assertIsNone(bot) + # delete bots + store.delete_bot(enterprise_id="EO111", team_id="TO222") + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNotNone(bot) + + store.delete_bot(enterprise_id="EO111", team_id=None) + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNone(bot) + + # find installations i = store.find_installation(enterprise_id="EO111", team_id=None) self.assertIsNotNone(i) i = store.find_installation( @@ -104,3 +148,19 @@ def test_org_installation(self): self.assertIsNone(i) i = store.find_installation(enterprise_id=None, team_id="T222", user_id="U111") self.assertIsNone(i) + + # delete installations + store.delete_installation(enterprise_id="E111", team_id=None) + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id=None) + + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id=None, user_id="U111") + self.assertIsNone(i) + bot = store.find_bot(enterprise_id=None, team_id="T222") + self.assertIsNone(bot) diff --git a/tests/slack_sdk/oauth/installation_store/test_interaface.py b/tests/slack_sdk/oauth/installation_store/test_interface.py similarity index 100% rename from tests/slack_sdk/oauth/installation_store/test_interaface.py rename to tests/slack_sdk/oauth/installation_store/test_interface.py diff --git a/tests/slack_sdk/oauth/installation_store/test_simple_cache.py b/tests/slack_sdk/oauth/installation_store/test_simple_cache.py index 2caa6d410..ad0d088c6 100644 --- a/tests/slack_sdk/oauth/installation_store/test_simple_cache.py +++ b/tests/slack_sdk/oauth/installation_store/test_simple_cache.py @@ -37,3 +37,20 @@ def test_save_and_find(self): self.assertIsNone(bot) bot = store.find_bot(enterprise_id="E111", team_id="T111") self.assertIsNotNone(bot) + + # delete and find + sqlite3_store = SQLite3InstallationStore( + database="logs/cacheable.db", client_id="111.222" + ) + sqlite3_store.init() + store = CacheableInstallationStore(sqlite3_store) + + store.save(installation) + bot = store.find_bot(enterprise_id="E111", team_id="T111") + self.assertIsNotNone(bot) + + os.remove("logs/cacheable.db") + bot = sqlite3_store.find_bot(enterprise_id="E111", team_id="T111") + self.assertIsNone(bot) + bot = store.find_bot(enterprise_id="E111", team_id="T111") + self.assertIsNotNone(bot) diff --git a/tests/slack_sdk/oauth/installation_store/test_sqlalchemy.py b/tests/slack_sdk/oauth/installation_store/test_sqlalchemy.py index 3f61e1483..53d8e273f 100644 --- a/tests/slack_sdk/oauth/installation_store/test_sqlalchemy.py +++ b/tests/slack_sdk/oauth/installation_store/test_sqlalchemy.py @@ -34,33 +34,64 @@ def test_save_and_find(self): ) self.store.save(installation) - bot = self.store.find_bot(enterprise_id="E111", team_id="T111") + store = self.store + + # find bots + bot = store.find_bot(enterprise_id="E111", team_id="T111") self.assertIsNotNone(bot) - bot = self.store.find_bot(enterprise_id="E111", team_id="T222") + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + bot = store.find_bot(enterprise_id=None, team_id="T111") self.assertIsNone(bot) - bot = self.store.find_bot(enterprise_id=None, team_id="T111") + + # delete bots + store.delete_bot(enterprise_id="E111", team_id="T222") + bot = store.find_bot(enterprise_id="E111", team_id="T222") self.assertIsNone(bot) - i = self.store.find_installation(enterprise_id="E111", team_id="T111") + # find installations + i = store.find_installation(enterprise_id="E111", team_id="T111") self.assertIsNotNone(i) - i = self.store.find_installation(enterprise_id="E111", team_id="T222") + i = store.find_installation(enterprise_id="E111", team_id="T222") self.assertIsNone(i) - i = self.store.find_installation(enterprise_id=None, team_id="T111") + i = store.find_installation(enterprise_id=None, team_id="T111") self.assertIsNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="E111", team_id="T111", user_id="U111" ) self.assertIsNotNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="E111", team_id="T111", user_id="U222" ) self.assertIsNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="E111", team_id="T222", user_id="U111" ) self.assertIsNone(i) + # delete installations + store.delete_installation(enterprise_id="E111", team_id="T111", user_id="U111") + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id="T111") + + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + def test_org_installation(self): installation = Installation( app_id="AO111", @@ -74,40 +105,67 @@ def test_org_installation(self): ) self.store.save(installation) - bot = self.store.find_bot(enterprise_id="EO111", team_id=None) + store = self.store + + # find bots + bot = store.find_bot(enterprise_id="EO111", team_id=None) self.assertIsNotNone(bot) - bot = self.store.find_bot( + bot = store.find_bot( enterprise_id="EO111", team_id="TO222", is_enterprise_install=True ) self.assertIsNotNone(bot) - bot = self.store.find_bot(enterprise_id="EO111", team_id="TO222") + bot = store.find_bot(enterprise_id="EO111", team_id="TO222") self.assertIsNone(bot) - bot = self.store.find_bot(enterprise_id=None, team_id="TO111") + bot = store.find_bot(enterprise_id=None, team_id="TO111") self.assertIsNone(bot) - i = self.store.find_installation(enterprise_id="EO111", team_id=None) + # delete bots + store.delete_bot(enterprise_id="EO111", team_id="TO222") + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNotNone(bot) + + store.delete_bot(enterprise_id="EO111", team_id=None) + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNone(bot) + + # find installations + i = store.find_installation(enterprise_id="EO111", team_id=None) self.assertIsNotNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="EO111", team_id="T111", is_enterprise_install=True ) self.assertIsNotNone(i) - i = self.store.find_installation(enterprise_id="EO111", team_id="T222") + i = store.find_installation(enterprise_id="EO111", team_id="T222") self.assertIsNone(i) - i = self.store.find_installation(enterprise_id=None, team_id="T111") + i = store.find_installation(enterprise_id=None, team_id="T111") self.assertIsNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="EO111", team_id=None, user_id="UO111" ) self.assertIsNotNone(i) - i = self.store.find_installation( + i = store.find_installation( enterprise_id="E111", team_id="T111", is_enterprise_install=True, user_id="U222", ) self.assertIsNone(i) - i = self.store.find_installation( - enterprise_id=None, team_id="T222", user_id="U111" - ) + i = store.find_installation(enterprise_id=None, team_id="T222", user_id="U111") self.assertIsNone(i) + + # delete installations + store.delete_installation(enterprise_id="E111", team_id=None) + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id=None) + + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id=None, user_id="U111") + self.assertIsNone(i) + bot = store.find_bot(enterprise_id=None, team_id="T222") + self.assertIsNone(bot) diff --git a/tests/slack_sdk/oauth/installation_store/test_sqlite3.py b/tests/slack_sdk/oauth/installation_store/test_sqlite3.py index fbb61c983..6a831a38b 100644 --- a/tests/slack_sdk/oauth/installation_store/test_sqlite3.py +++ b/tests/slack_sdk/oauth/installation_store/test_sqlite3.py @@ -36,6 +36,7 @@ def test_save_and_find(self): ) store.save(installation) + # find bots bot = store.find_bot(enterprise_id="E111", team_id="T111") self.assertIsNotNone(bot) bot = store.find_bot(enterprise_id="E111", team_id="T222") @@ -43,6 +44,12 @@ def test_save_and_find(self): bot = store.find_bot(enterprise_id=None, team_id="T111") self.assertIsNone(bot) + # delete bots + store.delete_bot(enterprise_id="E111", team_id="T222") + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + + # find installations i = store.find_installation(enterprise_id="E111", team_id="T111") self.assertIsNotNone(i) i = store.find_installation(enterprise_id="E111", team_id="T222") @@ -63,6 +70,28 @@ def test_save_and_find(self): ) self.assertIsNone(i) + # delete installations + store.delete_installation(enterprise_id="E111", team_id="T111", user_id="U111") + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id="T111") + + i = store.find_installation(enterprise_id="E111", team_id="T111") + self.assertIsNone(i) + i = store.find_installation( + enterprise_id="E111", team_id="T111", user_id="U111" + ) + self.assertIsNone(i) + bot = store.find_bot(enterprise_id="E111", team_id="T222") + self.assertIsNone(bot) + def test_org_installation(self): store = SQLite3InstallationStore(database="logs/test.db", client_id="111.222") installation = Installation( @@ -77,6 +106,7 @@ def test_org_installation(self): ) store.save(installation) + # find bots bot = store.find_bot(enterprise_id="EO111", team_id=None) self.assertIsNotNone(bot) bot = store.find_bot( @@ -88,6 +118,16 @@ def test_org_installation(self): bot = store.find_bot(enterprise_id=None, team_id="TO111") self.assertIsNone(bot) + # delete bots + store.delete_bot(enterprise_id="EO111", team_id="TO222") + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNotNone(bot) + + store.delete_bot(enterprise_id="EO111", team_id=None) + bot = store.find_bot(enterprise_id="EO111", team_id=None) + self.assertIsNone(bot) + + # find installations i = store.find_installation(enterprise_id="EO111", team_id=None) self.assertIsNotNone(i) i = store.find_installation( @@ -112,3 +152,19 @@ def test_org_installation(self): self.assertIsNone(i) i = store.find_installation(enterprise_id=None, team_id="T222", user_id="U111") self.assertIsNone(i) + + # delete installations + store.delete_installation(enterprise_id="E111", team_id=None) + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + + # delete all + store.save(installation) + store.delete_all(enterprise_id="E111", team_id=None) + + i = store.find_installation(enterprise_id="E111", team_id=None) + self.assertIsNone(i) + i = store.find_installation(enterprise_id="E111", team_id=None, user_id="U111") + self.assertIsNone(i) + bot = store.find_bot(enterprise_id=None, team_id="T222") + self.assertIsNone(bot)