Skip to content

Commit 0e1c672

Browse files
committed
fix(slack): resolve httpx protocol errors and unbound variables
- Removed markdown formatting from Slack API URLs to fix UnsupportedProtocol. - Added safety checks for response_url to prevent 500 errors in App Home interactions. - Initialized action_id and cast IDs to strings to satisfy Pylance strict mode.
1 parent 8574e7d commit 0e1c672

1 file changed

Lines changed: 72 additions & 98 deletions

File tree

backend/api/routes/feedback.py

Lines changed: 72 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ async def slack_interactions(request: Request):
5858
raise HTTPException(status_code=400, detail="Missing payload")
5959

6060
payload = json.loads(str(payload_str))
61-
user_id = str(payload.get("user", {}).get("id", "")) # Cast to str for Pylance
61+
user_id = str(payload.get("user", {}).get("id", ""))
6262
interaction_type = payload.get("type")
6363

6464
slack_token = (
@@ -72,120 +72,94 @@ async def slack_interactions(request: Request):
7272
action_id = action.get("action_id")
7373
response_url = payload.get("response_url")
7474

75-
if not response_url or not isinstance(response_url, str):
76-
logger.warning("slack_interaction_no_response_url", action_id=action_id)
77-
return Response(status_code=200)
78-
79-
blocks = payload.get("message", {}).get("blocks", [])
80-
raw_draft = blocks[1]["text"]["text"] if len(blocks) > 1 else ""
81-
draft_text = raw_draft.replace("```", "").strip()
82-
topic = "Медичний пост"
83-
84-
# УСІ перевірки action_id мають бути всередині цього блоку
75+
# --- ГРУПА 1: Дії, що відкривають модалки (response_url НЕ потрібен) ---
8576
if action_id == "action_open_upload_modal":
86-
logger.info("slack_home_upload_btn_clicked", user_id=user_id)
8777
modal_view = build_upload_modal()
8878
async with httpx.AsyncClient() as client:
89-
res = await client.post(
79+
await client.post(
9080
"https://slack.com/api/views.open",
9181
headers=headers,
9282
json={"trigger_id": trigger_id, "view": modal_view},
9383
)
94-
if not res.json().get("ok"):
95-
logger.error("slack_modal_error", error=res.json())
96-
97-
elif action_id == "action_publish_draft":
98-
logger.info("slack_draft_approved", user_id=user_id)
99-
await publish_post_task.kiq(
100-
post_id="temp_id", platform="telegram", content=draft_text
101-
)
102-
async with httpx.AsyncClient() as client:
103-
await client.post(
104-
response_url,
105-
json={
106-
"replace_original": True,
107-
"text": SLACK_UI["interact_approved_text"],
108-
"blocks": [
109-
{
110-
"type": "section",
111-
"text": {
112-
"type": "mrkdwn",
113-
"text": SLACK_UI["interact_approved_section"],
114-
},
115-
}
116-
],
117-
},
118-
)
84+
return Response(status_code=200)
11985

120-
elif action_id == "action_reject_draft":
121-
logger.info("slack_draft_rejected", user_id=user_id)
86+
if action_id == "action_open_generation_modal":
87+
modal_view = build_generation_modal(channel_id=user_id)
12288
async with httpx.AsyncClient() as client:
12389
await client.post(
124-
response_url,
125-
json={
126-
"replace_original": True,
127-
"text": SLACK_UI["interact_rejected_text"],
128-
"blocks": [
129-
{
130-
"type": "section",
131-
"text": {
132-
"type": "mrkdwn",
133-
"text": SLACK_UI["interact_rejected_section"],
134-
},
135-
}
136-
],
137-
},
138-
)
139-
140-
elif action_id == "action_edit_draft":
141-
logger.info("slack_draft_edit_opened", user_id=user_id)
142-
modal_view = build_approval_modal(
143-
topic=topic, draft=draft_text, platform="telegram"
144-
)
145-
async with httpx.AsyncClient() as client:
146-
res = await client.post(
14790
"https://slack.com/api/views.open",
14891
headers=headers,
14992
json={"trigger_id": trigger_id, "view": modal_view},
15093
)
151-
if not res.json().get("ok"):
152-
logger.error("slack_modal_error", error=res.json())
153-
154-
elif action_id == "action_regenerate_draft":
155-
logger.info("slack_draft_regenerate", user_id=user_id)
156-
channel_id = str(payload.get("channel", {}).get("id", ""))
157-
await generate_draft_task.kiq(
158-
topic=topic, platform="telegram", user_id=user_id, channel_id=channel_id
159-
) # type: ignore
160-
async with httpx.AsyncClient() as client:
161-
await client.post(
162-
response_url,
163-
json={
164-
"replace_original": True,
165-
"text": SLACK_UI["interact_regenerate_text"],
166-
"blocks": [
167-
{
168-
"type": "section",
169-
"text": {
170-
"type": "mrkdwn",
171-
"text": SLACK_UI["interact_regenerate_section"],
172-
},
173-
}
174-
],
175-
},
94+
return Response(status_code=200)
95+
96+
# --- ГРУПА 2: Дії з повідомленнями (response_url ОБОВ'ЯЗКОВИЙ) ---
97+
if action_id in [
98+
"action_publish_draft",
99+
"action_reject_draft",
100+
"action_edit_draft",
101+
"action_regenerate_draft",
102+
]:
103+
if not response_url:
104+
logger.warning(
105+
"slack_interaction_missing_url_for_message_action",
106+
action_id=action_id,
176107
)
108+
return Response(status_code=200)
109+
110+
# Логіка парсингу тексту повідомлення
111+
blocks = payload.get("message", {}).get("blocks", [])
112+
raw_draft = blocks[1]["text"]["text"] if len(blocks) > 1 else ""
113+
draft_text = raw_draft.replace("```", "").strip()
114+
topic = "Медичний пост"
177115

178-
elif action_id == "action_open_generation_modal":
179-
logger.info("slack_home_generation_btn_clicked", user_id=user_id)
180-
modal_view = build_generation_modal(channel_id=user_id)
181116
async with httpx.AsyncClient() as client:
182-
res = await client.post(
183-
"https://slack.com/api/views.open",
184-
headers=headers,
185-
json={"trigger_id": trigger_id, "view": modal_view},
186-
)
187-
if not res.json().get("ok"):
188-
logger.error("slack_modal_error", error=res.json())
117+
if action_id == "action_publish_draft":
118+
await publish_post_task.kiq(
119+
post_id="temp_id", platform="telegram", content=draft_text
120+
)
121+
await client.post(
122+
response_url,
123+
json={
124+
"replace_original": True,
125+
"text": SLACK_UI["interact_approved_text"],
126+
},
127+
)
128+
129+
elif action_id == "action_reject_draft":
130+
await client.post(
131+
response_url,
132+
json={
133+
"replace_original": True,
134+
"text": SLACK_UI["interact_rejected_text"],
135+
},
136+
)
137+
138+
elif action_id == "action_edit_draft":
139+
modal_view = build_approval_modal(
140+
topic=topic, draft=draft_text, platform="telegram"
141+
)
142+
await client.post(
143+
"https://slack.com/api/views.open",
144+
headers=headers,
145+
json={"trigger_id": trigger_id, "view": modal_view},
146+
)
147+
148+
elif action_id == "action_regenerate_draft":
149+
channel_id = str(payload.get("channel", {}).get("id", ""))
150+
await generate_draft_task.kiq( # type: ignore[call-overload]
151+
topic=topic,
152+
platform="telegram",
153+
user_id=user_id,
154+
channel_id=channel_id,
155+
)
156+
await client.post(
157+
response_url,
158+
json={
159+
"replace_original": True,
160+
"text": SLACK_UI["interact_regenerate_text"],
161+
},
162+
)
189163

190164
return Response(status_code=200)
191165

0 commit comments

Comments
 (0)