LiKenun commited on
Commit
4d8370b
·
1 Parent(s): 775cc8d

Resolve user identifiers to display or real names for incoming Slack messages

Browse files
src/ctp_slack_bot/app.py CHANGED
@@ -34,7 +34,7 @@ async def main() -> None:
34
  container.schedule_service()
35
 
36
  # Start the Slack socket mode handler in the background.
37
- socket_mode_handler = container.socket_mode_handler()
38
  slack_bolt_task = create_task(socket_mode_handler.start_async())
39
  shutdown_signal_handler = create_shutdown_signal_handler()
40
  loop = get_running_loop()
 
34
  container.schedule_service()
35
 
36
  # Start the Slack socket mode handler in the background.
37
+ socket_mode_handler = await container.socket_mode_handler()
38
  slack_bolt_task = create_task(socket_mode_handler.start_async())
39
  shutdown_signal_handler = create_shutdown_signal_handler()
40
  loop = get_running_loop()
src/ctp_slack_bot/services/slack_service.py CHANGED
@@ -1,8 +1,10 @@
1
- from dependency_injector.resources import Resource
2
  from loguru import logger
3
  from openai import OpenAI
4
  from pydantic import BaseModel
 
5
  from slack_bolt.async_app import AsyncApp
 
6
  from typing import Any, Mapping, Self
7
 
8
  from ctp_slack_bot.enums import EventType
@@ -10,6 +12,9 @@ from ctp_slack_bot.models import SlackMessage, SlackResponse
10
  from ctp_slack_bot.services.event_brokerage_service import EventBrokerageService
11
 
12
 
 
 
 
13
  class SlackService(BaseModel):
14
  """
15
  Service for interfacing with Slack.
@@ -17,6 +22,7 @@ class SlackService(BaseModel):
17
 
18
  event_brokerage_service: EventBrokerageService
19
  slack_bolt_app: AsyncApp
 
20
 
21
  class Config:
22
  arbitrary_types_allowed = True
@@ -28,6 +34,7 @@ class SlackService(BaseModel):
28
  logger.debug("Created {}", self.__class__.__name__)
29
 
30
  def adapt_event_payload(self: Self, event: Mapping[str, Any]) -> SlackMessage:
 
31
  return SlackMessage(
32
  type=event.get("type"),
33
  subtype=event.get("subtype"),
@@ -36,7 +43,7 @@ class SlackService(BaseModel):
36
  user=event.get("user"),
37
  bot_id=event.get("bot_id"),
38
  thread_ts=event.get("thread_ts"),
39
- text=event.get("text", ""),
40
  ts=event.get("ts"),
41
  event_ts=event.get("event_ts")
42
  )
@@ -57,13 +64,23 @@ class SlackService(BaseModel):
57
  logger.debug("Received app mention for processing: {}", body.get("event", {}).get("text"))
58
  await self.process_message(body)
59
 
60
- def register(self: Self) -> None:
61
  self.slack_bolt_app.event("message")(self.handle_message_event)
62
  self.slack_bolt_app.event("app_mention")(self.handle_app_mention_event)
63
  logger.debug("Registered 2 handlers for Slack Bolt message and app mention events.")
64
 
65
- class SlackServiceResource(Resource):
66
- def init(self: Self, event_brokerage_service: EventBrokerageService, slack_bolt_app: AsyncApp) -> SlackService:
67
- slack_service = SlackService(event_brokerage_service=event_brokerage_service, slack_bolt_app=slack_bolt_app)
68
- slack_service.register()
 
 
 
 
 
 
 
 
 
 
69
  return slack_service
 
1
+ from dependency_injector.resources import AsyncResource
2
  from loguru import logger
3
  from openai import OpenAI
4
  from pydantic import BaseModel
5
+ from re import compile as compile_re
6
  from slack_bolt.async_app import AsyncApp
7
+ from slack_sdk.web.async_slack_response import AsyncSlackResponse
8
  from typing import Any, Mapping, Self
9
 
10
  from ctp_slack_bot.enums import EventType
 
12
  from ctp_slack_bot.services.event_brokerage_service import EventBrokerageService
13
 
14
 
15
+ SLACK_USER_MENTION_PATTERN = compile_re(r"<@([A-Z0-9]+)>")
16
+
17
+
18
  class SlackService(BaseModel):
19
  """
20
  Service for interfacing with Slack.
 
22
 
23
  event_brokerage_service: EventBrokerageService
24
  slack_bolt_app: AsyncApp
25
+ user_id_name_map: dict[str, str] # This is deliberately mutable; the map may change as new users are encountered.
26
 
27
  class Config:
28
  arbitrary_types_allowed = True
 
34
  logger.debug("Created {}", self.__class__.__name__)
35
 
36
  def adapt_event_payload(self: Self, event: Mapping[str, Any]) -> SlackMessage:
37
+ text = SLACK_USER_MENTION_PATTERN.sub(lambda match: f"@{self.user_id_name_map.get(match.group(1))}", event.get("text", "")) # TODO: permit look-up of Slack again when not found.
38
  return SlackMessage(
39
  type=event.get("type"),
40
  subtype=event.get("subtype"),
 
43
  user=event.get("user"),
44
  bot_id=event.get("bot_id"),
45
  thread_ts=event.get("thread_ts"),
46
+ text=text,
47
  ts=event.get("ts"),
48
  event_ts=event.get("event_ts")
49
  )
 
64
  logger.debug("Received app mention for processing: {}", body.get("event", {}).get("text"))
65
  await self.process_message(body)
66
 
67
+ def initialize(self: Self) -> None:
68
  self.slack_bolt_app.event("message")(self.handle_message_event)
69
  self.slack_bolt_app.event("app_mention")(self.handle_app_mention_event)
70
  logger.debug("Registered 2 handlers for Slack Bolt message and app mention events.")
71
 
72
+
73
+ class SlackServiceResource(AsyncResource):
74
+ async def init(self: Self, event_brokerage_service: EventBrokerageService, slack_bolt_app: AsyncApp) -> SlackService:
75
+ match await slack_bolt_app.client.users_list():
76
+ case AsyncSlackResponse(status_code=200, data={"ok": True, "members": users}):
77
+ user_id_name_map = {user["id"]: user["profile"]["display_name"] or user["real_name"]
78
+ for user
79
+ in users}
80
+ logger.debug("Obtained a list of {} user name(s) for the workspace: {}", len(user_id_name_map), user_id_name_map)
81
+ case something:
82
+ user_id_name_map = {}
83
+ logger.error("Could not obtain a list of user name for the workspace.")
84
+ slack_service = SlackService(event_brokerage_service=event_brokerage_service, slack_bolt_app=slack_bolt_app, user_id_name_map=user_id_name_map)
85
+ slack_service.initialize()
86
  return slack_service