async def test_self_events(self): app = AsyncApp(client=self.web_client) app.event("reaction_added")(whats_up) self_event = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "type": "reaction_added", "user": "******", # bot_user_id "item": { "type": "message", "channel": "C111", "ts": "1599529504.000400", }, "reaction": "heart_eyes", "item_user": "******", "event_ts": "1599616881.000800", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authed_users": ["W111"], } request = AsyncBoltRequest(body=self_event, mode="socket_mode") response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 await asyncio.sleep(1) # wait a bit after auto ack() # The listener should not be executed assert self.mock_received_requests.get("/chat.postMessage") is None
async def test_middleware_skip(self): app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret) app.event("app_mention", middleware=[skip_middleware])(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 404 assert self.mock_received_requests["/auth.test"] == 1
async def test_stable_auto_ack(self): app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret,) app.event("reaction_added")(always_failing) for _ in range(10): request = self.build_valid_reaction_added_request() response = await app.async_dispatch(request) assert response.status == 200
async def test_middleware_skip(self): app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret) app.event("app_mention", middleware=[skip_middleware])(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 404 await assert_auth_test_count_async(self, 1)
async def test_reaction_added(self): app = AsyncApp(client=self.web_client) app.event("reaction_added")(whats_up) request = self.build_valid_reaction_added_request() response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_app_mention(self): app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret,) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_self_events_disabled(self): app = AsyncApp(client=self.web_client, ignoring_self_events_enabled=False) app.event("reaction_added")(whats_up) request = AsyncBoltRequest(body=self_event, mode="socket_mode") response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 0) await asyncio.sleep(1) # wait a bit after auto ack() # The listener should be executed assert self.mock_received_requests.get("/chat.postMessage") == 1
async def test_process_before_response(self): app = AsyncApp(client=self.web_client, process_before_response=True,) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 # no sleep here assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_bot_only_default_off(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, installation_store=BotOnlyMemoryInstallationStore(), ) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() with pytest.raises(ValueError): await app.async_dispatch(request)
def test_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, ) async def event_handler(): pass app.event("app_mention")(event_handler) input = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "client_msg_id": "9cbd4c5b-7ddf-4ede-b479-ad21fca66d63", "type": "app_mention", "text": "<@W111> Hi there!", "user": "******", "ts": "1595926230.009600", "team": "T111", "channel": "C111", "event_ts": "1595926230.009600", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1595926230, "authed_users": ["W111"], } timestamp, body = str(int(time())), json.dumps(input) async def endpoint(req: Request): return await app_handler.handle(req) api = Starlette( debug=True, routes=[ Route("/slack/events", endpoint=endpoint, methods=["POST"]) ], ) app_handler = AsyncSlackRequestHandler(app) client = TestClient(api) response = client.post( "/slack/events", data=body, headers=self.build_headers(timestamp, body), ) assert response.status_code == 200 assert self.mock_received_requests["/auth.test"] == 1
async def test_self_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, authorize=authorize, ) app.event("reaction_added")(whats_up) self_event = { "token": "verification_token", "team_id": "T_SOURCE", "enterprise_id": "E_SOURCE", "api_app_id": "A111", "event": { "type": "reaction_added", "user": "******", # bot_user_id "item": { "type": "message", "channel": "C111", "ts": "1599529504.000400", }, "reaction": "heart_eyes", "item_user": "******", "event_ts": "1599616881.000800", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authorizations": [{ "enterprise_id": "E_INSTALLED", "team_id": "T_INSTALLED", "user_id": "W111", "is_bot": True, "is_enterprise_install": False, }], } timestamp, body = str(int(time())), json.dumps(self_event) request = AsyncBoltRequest(body=body, headers=self.build_headers(timestamp, body)) response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 await asyncio.sleep(1) # wait a bit after auto ack() # The listener should not be executed assert self.mock_received_requests.get("/chat.postMessage") is None
async def test_bot_only_oauth_flow(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, oauth_flow=AsyncOAuthFlow(settings=oauth_settings_bot_only), ) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_process_before_response(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, authorize=authorize, process_before_response=True, ) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) # no sleep here assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_bot_only(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, installation_store=BotOnlyMemoryInstallationStore(), installation_store_bot_only=True, ) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_bot_only_oauth_settings_conflicts(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, oauth_settings=oauth_settings, installation_store_bot_only=True, ) app.event("app_mention")(whats_up) request = self.build_valid_app_mention_request() response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_default(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, ) app.event("app_mention")(whats_up) timestamp, body = str(int(time())), json.dumps(app_mention_body) request = AsyncBoltRequest( body=body, headers=self.build_headers(timestamp, body) ) response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, ) async def event_handler(): pass app.event("app_mention")(event_handler) input = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "client_msg_id": "9cbd4c5b-7ddf-4ede-b479-ad21fca66d63", "type": "app_mention", "text": "<@W111> Hi there!", "user": "******", "ts": "1595926230.009600", "team": "T111", "channel": "C111", "event_ts": "1595926230.009600", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1595926230, "authed_users": ["W111"], } timestamp, body = str(int(time())), json.dumps(input) api = Sanic(name=self.unique_sanic_app_name()) app_handler = AsyncSlackRequestHandler(app) @api.post("/slack/events") async def endpoint(req: Request): return await app_handler.handle(req) _, response = await api.asgi_client.post( url="/slack/events", data=body, headers=self.build_headers(timestamp, body), ) assert response.status_code == 200 assert_auth_test_count(self, 1)
async def test_simultaneous_requests(self): app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret,) app.event("app_mention")(random_sleeper) request = self.build_valid_app_mention_request() times = 10 tasks = [] for i in range(times): tasks.append(asyncio.ensure_future(app.async_dispatch(request))) await asyncio.sleep(5) # Verifies all the tasks have been completed with 200 OK assert sum([t.result().status for t in tasks if t.done()]) == 200 * times assert self.mock_received_requests["/auth.test"] == times assert self.mock_received_requests["/chat.postMessage"] == times
async def test_disabled(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, request_verification_enabled=False, ) app.event("app_mention")(whats_up) # request including invalid headers expired = int(time()) - 3600 timestamp, body = str(expired), json.dumps(app_mention_body) request = AsyncBoltRequest( body=body, headers=self.build_headers(timestamp, body) ) response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) await asyncio.sleep(1) # wait a bit after auto ack() assert self.mock_received_requests["/chat.postMessage"] == 1
async def test_joined_left_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, ) app.event("reaction_added")(whats_up) join_event_body = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "type": "member_joined_channel", "user": "******", # other user "channel": "C111", "channel_type": "C", "team": "T111", "inviter": "U222", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authed_users": ["W111"], } left_event_body = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "type": "member_left_channel", "user": "******", # other user "channel": "C111", "channel_type": "C", "team": "T111", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authed_users": ["W111"], } @app.event("member_joined_channel") async def handle_member_joined_channel(say): await say("What's up?") @app.event("member_left_channel") async def handle_member_left_channel(say): await say("What's up?") timestamp, body = str(int(time())), json.dumps(join_event_body) request = AsyncBoltRequest(body=body, headers=self.build_headers(timestamp, body)) response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 timestamp, body = str(int(time())), json.dumps(left_event_body) request = AsyncBoltRequest(body=body, headers=self.build_headers(timestamp, body)) response = await app.async_dispatch(request) assert response.status == 200 await asyncio.sleep(1) # wait a bit after auto ack() # The listeners should be executed assert self.mock_received_requests.get("/chat.postMessage") == 2
class SlackTeam: def __init__(self, data: dict, slack: 'Slack'): self.slack = slack self.bot = self.slack.bot self.team_id = data['team_id'] self.token = data['token'] self.bot_id = data['bot_id'] self.name = self.team_id self.app = AsyncApp(token=self.token) self.app.view("socket_modal_submission")(self.submission) self.app.event("message")(self.slack_message) self.app.event("member_joined_channel")(self.slack_member_joined) self.app.event("channel_left")(self.slack_channel_left) self.handler = AsyncSocketModeHandler(self.app, config.SLACK_APP_TOKEN) self.bot.loop.create_task(self.handler.start_async()) self.bot.add_listener(self.on_message, 'on_message') self.bot.add_listener(self.on_raw_message_edit, 'on_raw_message_edit') self.bot.add_listener(self.on_raw_message_delete, 'on_raw_message_delete') self.channels: list[SlackChannel] = [] self.members: list[SlackMember] = [] self.slack.bot.loop.create_task(self.get_team_info()) self.discord_messages: TTLCache[int, DiscordMessage] = TTLCache(ttl=600.0, maxsize=500) self.slack_messages: TTLCache[str, SlackMessage] = TTLCache(ttl=600.0, maxsize=500) self.message_links = TTLCache(ttl=86400.0, maxsize=1000) self.initialize_data() self.messages_cached = asyncio.Event() self.members_cached = asyncio.Event() self.channels_cached = asyncio.Event() self.slack.bot.loop.create_task(self.cache_members()) self.slack.bot.loop.create_task(self.cache_channels()) self.slack.bot.loop.create_task(self.cache_messages()) def initialize_data(self): """Initilises the data in the database if needed.""" data = db.slack_bridge.find_one({'team_id': self.team_id}) if not data: data = { 'team_id': self.team_id, 'aliases': [], 'bridges': [], 'tokens': {} } db.slack_bridge.insert_one(data) async def get_team_info(self): team_data = await self.app.client.team_info() self.name = team_data['team']['name'] async def get_channels(self) -> list[dict]: """Function for getting channels, makes call to slack api and filters out channels bot isnt member of.""" channels_data = await self.app.client.conversations_list( team_id=self.team_id) return [ channel for channel in channels_data['channels'] if channel['is_member'] ] async def get_members(self) -> list[dict]: """Function for getting members, makes call to slack api and filters out bot accounts and slack bot account.""" members_data = await self.app.client.users_list(team_id=self.team_id) return [ member for member in members_data['members'] if not member['is_bot'] and not member['id'] == 'USLACKBOT' ] async def add_user(self, user_id: str): user_data = await self.app.client.users_info(user=user_id) slack_member = SlackMember(user_data['user'], self.slack) await slack_member.get_discord_member() self.members[slack_member.team_id].append(slack_member) return slack_member def get_user(self, slack_id: str = None, *, discord_id: int = None) -> Optional[SlackMember]: """Get SlackMember via slack id or discord id.""" for member in self.members: if (slack_id is not None and member.id == slack_id) or \ (discord_id is not None and member.discord_member and member.discord_member.id == discord_id): return member def get_channel(self, slack_id: str = None, *, discord_id: int = None) -> Optional[SlackChannel]: """Get SlackChannel via slack id or discord id.""" for channel in self.channels: if (slack_id is not None and channel.id == slack_id) or \ (discord_id is not None and channel.discord_channel and channel.discord_channel.id == discord_id): return channel async def cache_messages(self): """Cache messages in the database.""" await self.members_cached.wait() await self.channels_cached.wait() messages = db.slack_messages.find({ 'team_id': self.team_id }).sort('timestamp', 1) for message in messages: twenty_four_hours = 24 * 60 * 60 if time.time() - message['timestamp'] > twenty_four_hours: db.slack_messages.delete_one(message) continue if message['origin'] == 'discord': self.message_links[message['discord_message_id']] = message[ 'slack_message_id'] elif message['origin'] == 'slack': self.message_links[message['slack_message_id']] = message[ 'discord_message_id'] self.messages_cached.set() self.slack.bot.logger.debug( f'{len(self.message_links)} Slack and Discord messages cached for team [{self.team_id}]' ) async def cache_channels(self): """Caches channels.""" channels = await self.get_channels() for channel_data in channels: if self.get_channel(channel_data['id']): continue channel = SlackChannel( team=self, channel_id=channel_data['id'], slack=self.slack, ) self.channels.append(channel) self.channels_cached.set() self.slack.bot.logger.debug( f'{len(channels)} Slack channels cached for team [{self.team_id}]') async def cache_members(self): """Caches members.""" members = await self.get_members() for member_data in members: if self.get_user(member_data['id']): continue member = SlackMember( data=member_data, slack=self.slack, ) self.slack.bot.loop.create_task(member.get_discord_member()) self.members.append(member) self.members_cached.set() self.slack.bot.logger.debug( f'{len(members)} Slack member cached for team [{self.team_id}]') async def delete_discord_message(self, channel_id: int, message_id: int, *, ts: str = None): await self.slack.bot.http.delete_message(channel_id, message_id) if ts in self.slack_messages: del self.slack_messages[ts] db.slack_messages.delete_one({'slack_message_id': ts}) async def delete_slack_message(self, message_id: str, discord_channel_id: int, *, discord_message_id: int = None): slack_channel = self.get_channel(discord_id=discord_channel_id) await self.app.client.chat_delete(channel=slack_channel.id, ts=message_id) if discord_message_id in self.discord_messages: del self.discord_messages[discord_message_id] db.slack_messages.delete_one( {'discord_message_id': discord_message_id}) async def get_slack_message( self, channel_id: str, message_id: str, discord_message_id: int = None) -> Optional[SlackMessage]: if message_id is None: return result = await self.app.client.conversations_history( channel=channel_id, inclusive=True, oldest=message_id, limit=1) if not result or not result['messages']: return message = result['messages'][0] data = { 'event': { 'team_id': message['team_id'], 'user': message['user'] if 'user' in message else message['username'], 'discord_message_id': discord_message_id, 'channel': channel_id, 'text': message['text'], 'ts': message_id, 'files': [], 'subtype': '' } } return SlackMessage(data, self.slack) async def get_discord_message( self, channel_id: int, message_id: int, slack_message_id: str = None) -> Optional[DiscordMessage]: channel = self.slack.bot.get_channel(channel_id) try: message = await channel.fetch_message(message_id) except: # most-likely errors when message has been deleted db.slack_messages.delete_one({'discord_message_id': message_id}) return if message: discord_message = DiscordMessage(message, self.slack) discord_message.slack_message_id = slack_message_id return discord_message else: db.slack_messages.delete_one({'discord_message_id': message_id}) async def submission(self, ack): """Function that acknowledges events.""" await ack() async def slack_channel_left(self, body: dict): """Function called when bot leaves a channel""" event = body['event'] channel_id = event['channel'] channel = self.get_channel(channel_id) if channel: db.slack_bridge.update_one( {'team_id': self.team_id}, {'$pull': { 'bridges': { 'slack_channel_id': channel_id } }}) self.channels.remove(channel) async def slack_member_joined(self, body: dict): event = body['event'] channel_id = event['channel'] user_id = event['user'] if user_id == self.bot_id: channel = SlackChannel(self, channel_id, self.slack) self.channels.append(channel) else: user_data = await self.app.client.users_info(user=user_id) member = SlackMember(user_data['user'], self.slack) self.members.append(member) async def handle_delete_message(self, body: dict): event = body['event'] ts = event['deleted_ts'] channel_id = event['channel'] slack_message = self.slack_messages.get(ts, None) slack_message_link = self.message_links.get(ts, None) if not slack_message: slack_channel = self.get_channel(slack_id=channel_id) if not slack_channel.discord_channel or not slack_message_link: return return await self.delete_discord_message( slack_channel.discord_channel.id, slack_message_link, ts=ts) return await slack_message.delete() async def handle_edit_message(self, body: dict): event = body['event'] ts = event['message']['ts'] channel_id = event['channel'] # check if message was edited by the bot edit_message = next( filter(lambda dm: dm.slack_message_id == ts, self.discord_messages.values()), None) if edit_message: return slack_message = self.slack_messages.get(ts, None) if not slack_message: slack_message_link = self.message_links[ ts] if ts in self.message_links else None slack_message = await self.get_slack_message( channel_id, ts, slack_message_link) if slack_message: slack_message.text = event['message']['text'] asyncio.create_task(slack_message.send_to_discord(edit=True)) async def slack_message(self, body): """Function called on message even from slack.""" await self.messages_cached.wait() event = body['event'] is_delete = 'subtype' in body['event'] and body['event'][ 'subtype'] == 'message_deleted' is_edit = 'subtype' in body['event'] and body['event'][ 'subtype'] == 'message_changed' is_bot_message = 'subtype' in body['event'] and body['event'][ 'subtype'] == 'bot_message' if is_edit: return await self.handle_edit_message(event) if is_delete: return await self.handle_delete_message(event) if is_bot_message: return message = SlackMessage(body, self.slack) asyncio.create_task(message.send_to_discord()) # Discord events async def on_raw_message_delete(self, payload: discord.RawMessageDeleteEvent): channel_id = payload.channel_id slack_channel = self.get_channel(discord_id=channel_id) if not slack_channel: return team = slack_channel.team await team.messages_cached.wait() message_id = payload.message_id discord_message = team.discord_messages.get(message_id, None) if not discord_message: discord_message_link = team.message_links[message_id] return await team.delete_slack_message( discord_message_link, channel_id, discord_message_id=message_id) await discord_message.delete() async def on_raw_message_edit(self, payload: discord.RawMessageUpdateEvent): """ Function called on on_edit_message event, used for dealing with message edit events on the discord side and doing the same on the slack end. """ if 'content' not in payload.data: return channel_id = payload.channel_id slack_channel = self.get_channel(discord_id=channel_id) if not slack_channel: return team = slack_channel.team await team.messages_cached.wait() message_id = payload.message_id content = payload.data['content'] cached_message = team.discord_messages.get(message_id, None) if not cached_message: cached_message_link = team.message_links.get(message_id, None) cached_message = await team.get_discord_message( channel_id, message_id, cached_message_link) if cached_message is None: return cached_message.text = content await cached_message.send_to_slack(edit=True) async def on_message(self, message: discord.Message): """Function call on on_message event, used for identifying discord bridge channel and forwarding the messages to slack.""" # ignore webhook messages and pms if not message.guild or message.webhook_id: return slack_channel = self.get_channel(discord_id=message.channel.id) if not slack_channel: return await self.messages_cached.wait() discord_message = DiscordMessage(message, self.slack) await discord_message.send_to_slack()
async def test_invalid_message_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, ) async def handle(): pass # valid app.event("message")(handle) with pytest.raises(ValueError): app.event("message.channels")(handle) with pytest.raises(ValueError): app.event("message.groups")(handle) with pytest.raises(ValueError): app.event("message.im")(handle) with pytest.raises(ValueError): app.event("message.mpim")(handle) with pytest.raises(ValueError): app.event(re.compile("message\\..*"))(handle) with pytest.raises(ValueError): app.event({"type": "message.channels"})(handle) with pytest.raises(ValueError): app.event({"type": re.compile("message\\..*")})(handle)
async def test_self_joined_left_events(self): app = AsyncApp( client=self.web_client, signing_secret=self.signing_secret, authorize=authorize, ) app.event("reaction_added")(whats_up) join_event_body = { "token": "verification_token", "team_id": "T_SOURCE", "enterprise_id": "E_SOURCE", "api_app_id": "A111", "event": { "type": "member_joined_channel", "user": "******", # bot_user_id "channel": "C111", "channel_type": "C", "team": "T_INSTALLED", "inviter": "U222", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authorizations": [ { "enterprise_id": "E_INSTALLED", "team_id": "T_INSTALLED", "user_id": "W111", "is_bot": True, "is_enterprise_install": False, } ], } left_event_body = { "token": "verification_token", "team_id": "T_SOURCE", "enterprise_id": "E_SOURCE", "api_app_id": "A111", "event": { "type": "member_left_channel", "user": "******", # bot_user_id "channel": "C111", "channel_type": "C", "team": "T_INSTALLED", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authorizations": [ { "enterprise_id": "E_INSTALLED", "team_id": "T_INSTALLED", "user_id": "W111", "is_bot": True, "is_enterprise_install": False, } ], } @app.event("member_joined_channel") async def handle_member_joined_channel(say): await say("What's up?") @app.event("member_left_channel") async def handle_member_left_channel(say): await say("What's up?") timestamp, body = str(int(time())), json.dumps(join_event_body) request = AsyncBoltRequest( body=body, headers=self.build_headers(timestamp, body) ) response = await app.async_dispatch(request) assert response.status == 200 await assert_auth_test_count_async(self, 1) timestamp, body = str(int(time())), json.dumps(left_event_body) request = AsyncBoltRequest( body=body, headers=self.build_headers(timestamp, body) ) response = await app.async_dispatch(request) assert response.status == 200 await asyncio.sleep(1) # wait a bit after auto ack() # The listeners should be executed assert self.mock_received_requests.get("/chat.postMessage") == 2
async def test_self_joined_left_events(self): app = AsyncApp(client=self.web_client) app.event("reaction_added")(whats_up) join_event_body = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "type": "member_joined_channel", "user": "******", # bot_user_id "channel": "C111", "channel_type": "C", "team": "T111", "inviter": "U222", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authed_users": ["W111"], } left_event_body = { "token": "verification_token", "team_id": "T111", "enterprise_id": "E111", "api_app_id": "A111", "event": { "type": "member_left_channel", "user": "******", # bot_user_id "channel": "C111", "channel_type": "C", "team": "T111", }, "type": "event_callback", "event_id": "Ev111", "event_time": 1599616881, "authed_users": ["W111"], } @app.event("member_joined_channel") async def handle_member_joined_channel(say): await say("What's up?") @app.event("member_left_channel") async def handle_member_left_channel(say): await say("What's up?") request = AsyncBoltRequest(body=join_event_body, mode="socket_mode") response = await app.async_dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 request = AsyncBoltRequest(body=left_event_body, mode="socket_mode") response = await app.async_dispatch(request) assert response.status == 200 await asyncio.sleep(1) # wait a bit after auto ack() # The listeners should be executed assert self.mock_received_requests.get("/chat.postMessage") == 2