Skip to content

Commit ac5bed4

Browse files
committed
Create base class for common block action functionality
1 parent 6ddadcc commit ac5bed4

2 files changed

Lines changed: 99 additions & 65 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from __future__ import annotations
2+
3+
from enum import IntEnum
4+
from typing import Any, Coroutine, MutableMapping, Optional
5+
6+
from slack import methods
7+
from slack.actions import Action
8+
from slack.io.abc import SlackAPI
9+
10+
11+
class BlockAction(Action):
12+
"""
13+
Base class for working with Block format Slack Action events.
14+
See https://api.slack.com/reference/messaging/blocks
15+
and https://api.slack.com/messaging/composing/layouts
16+
"""
17+
18+
def __init__(self, raw_action: MutableMapping):
19+
super().__init__(raw_action)
20+
21+
@property
22+
def original_message(self):
23+
return self["message"]
24+
25+
@property
26+
def channel(self):
27+
return self["channel"]["id"]
28+
29+
@property
30+
def blocks(self) -> list:
31+
return self.original_message["blocks"]
32+
33+
@blocks.setter
34+
def blocks(self, value) -> None:
35+
self.original_message["blocks"] = value
36+
37+
@property
38+
def attachments(self) -> list:
39+
return self.original_message.get("attachments", [])
40+
41+
@attachments.setter
42+
def attachments(self, value) -> None:
43+
self.original_message["attachments"] = value
44+
45+
@property
46+
def ts(self) -> str:
47+
return self.original_message["ts"]
48+
49+
@property
50+
def actions(self):
51+
return self["actions"]
52+
53+
@property
54+
def selected_option(self) -> Optional[dict]:
55+
if "selected_option" in self.actions[0]:
56+
return self.actions[0]["selected_option"]
57+
return None
58+
59+
def initial_option(self, index: IntEnum) -> str:
60+
"""
61+
Each section uses the `initial_option` key to store the latest
62+
option selected by the user
63+
"""
64+
accessory = self.blocks[index]["accessory"]
65+
if "initial_option" in accessory:
66+
return accessory["initial_option"]["value"]
67+
return ""
68+
69+
@property
70+
def update_params(self) -> dict:
71+
return {
72+
"channel": self.channel,
73+
"ts": self.ts,
74+
"blocks": self.blocks,
75+
"attachments": self.attachments,
76+
}
77+
78+
def validate_self(self) -> bool:
79+
"""
80+
Should be overridden if action has any validation
81+
"""
82+
return True
83+
84+
def update_message(self, slack: SlackAPI) -> Coroutine[Any, Any, dict]:
85+
return slack.query(methods.CHAT_UPDATE, self.update_params)
86+
87+
def add_errors(self):
88+
error_attachment = {
89+
"text": ":warning: Error - Cannot submit with current values :warning:",
90+
"color": "danger",
91+
}
92+
self.attachments = [error_attachment]
93+
94+
def clear_errors(self) -> None:
95+
self.attachments = []

pybot/endpoints/slack/message_templates/mentor_request.py

Lines changed: 4 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from pybot.endpoints.slack.utils.action_messages import now
99
from pybot.plugins.airtable.api import AirtableAPI
1010

11+
from .block_action import BlockAction
12+
1113

1214
class BlockIndex(IntEnum):
1315
SERVICE = 2
@@ -19,61 +21,10 @@ class BlockIndex(IntEnum):
1921
SUBMIT = 9
2022

2123

22-
class MentorRequest(Action):
24+
class MentorRequest(BlockAction):
2325
def __init__(self, raw_action: MutableMapping):
2426
super().__init__(raw_action)
2527

26-
if "original_message" not in self:
27-
self["original_message"] = {}
28-
29-
@property
30-
def channel(self):
31-
return self["channel"]["id"]
32-
33-
@property
34-
def original_message(self):
35-
return self["message"]
36-
37-
@property
38-
def blocks(self):
39-
return self.original_message["blocks"]
40-
41-
@blocks.setter
42-
def blocks(self, value):
43-
self.original_message["blocks"] = value
44-
45-
@property
46-
def attachments(self):
47-
return self.original_message.get("attachments", [])
48-
49-
@attachments.setter
50-
def attachments(self, value):
51-
self.original_message["attachments"] = value
52-
53-
@property
54-
def ts(self):
55-
return self.original_message["ts"]
56-
57-
@property
58-
def actions(self):
59-
return self["actions"]
60-
61-
@property
62-
def selected_option(self):
63-
if "selected_option" in self.actions[0]:
64-
return self.actions[0]["selected_option"]
65-
return None
66-
67-
def initial_option(self, index: BlockIndex) -> str:
68-
"""
69-
Each section uses the `initial_option` key to store the latest
70-
option selected by the user
71-
"""
72-
accessory = self.blocks[index]["accessory"]
73-
if "initial_option" in accessory:
74-
return accessory["initial_option"]["value"]
75-
return ""
76-
7728
@property
7829
def service(self):
7930
return self.initial_option(BlockIndex.SERVICE)
@@ -141,15 +92,6 @@ def affiliation(self, new_affiliation: str) -> None:
14192
if self.validate_self():
14293
self.clear_errors()
14394

144-
@property
145-
def update_params(self) -> dict:
146-
return {
147-
"channel": self.channel,
148-
"ts": self.ts,
149-
"blocks": self.blocks,
150-
"attachments": self.attachments,
151-
}
152-
15395
def validate_self(self) -> bool:
15496
if not self.service or not self.affiliation:
15597
return False
@@ -201,7 +143,7 @@ def submission_complete(self, slack: SlackAPI) -> Coroutine[Any, Any, dict]:
201143
"accessory": {
202144
"type": "button",
203145
"action_id": "cancel_btn",
204-
"text": {"type": "plain_text", "text": "Dimiss", "emoji": True},
146+
"text": {"type": "plain_text", "text": "Dismiss", "emoji": True},
205147
"value": "dismiss",
206148
},
207149
}
@@ -217,9 +159,6 @@ def clear_skillsets(self) -> None:
217159
def clear_errors(self) -> None:
218160
self.attachments = []
219161

220-
def update_message(self, slack: SlackAPI) -> Coroutine[Any, Any, dict]:
221-
return slack.query(methods.CHAT_UPDATE, self.update_params)
222-
223162

224163
class MentorRequestClaim(Action):
225164
def __init__(

0 commit comments

Comments
 (0)