mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 07:53:11 +00:00
Two root causes: - claim_open_shift ConditionExpression failed when no OVERRIDE record existed (shift available via weekly fallback). Added attribute_not_exists check so claims succeed for both missing and OPEN overrides. - Slack ack timeout: chat_postMessage took too long before respond() was called, causing Slack to show an error. Moved respond() first and made channel notifications best-effort with try/except.
This commit is contained in:
parent
a85eb0afd9
commit
61074dc7cc
2 changed files with 23 additions and 10 deletions
26
src/app.py
26
src/app.py
|
|
@ -121,7 +121,7 @@ def create_app(bot_token: str, signing_secret: str, schedule_channel: str | None
|
||||||
# ── Interactive button: pick up open shift ──────────────────────────
|
# ── Interactive button: pick up open shift ──────────────────────────
|
||||||
|
|
||||||
@app.action(re.compile(r"^pickup_"))
|
@app.action(re.compile(r"^pickup_"))
|
||||||
def handle_pickup_button(ack, body, client):
|
def handle_pickup_button(ack, body, client, respond):
|
||||||
ack()
|
ack()
|
||||||
action_id = body["actions"][0]["action_id"]
|
action_id = body["actions"][0]["action_id"]
|
||||||
remainder = action_id.replace("pickup_", "")
|
remainder = action_id.replace("pickup_", "")
|
||||||
|
|
@ -159,7 +159,7 @@ def create_app(bot_token: str, signing_secret: str, schedule_channel: str | None
|
||||||
blocks = build_shift_change_message(
|
blocks = build_shift_change_message(
|
||||||
user_id, date_str, "picked_up", employee["extension"], employee["name"]
|
user_id, date_str, "picked_up", employee["extension"], employee["name"]
|
||||||
)
|
)
|
||||||
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift picked up for {date_str}")
|
respond(response_type="in_channel", replace_original=False, blocks=blocks, text=f"Shift picked up for {date_str}")
|
||||||
|
|
||||||
# ── Subcommand handlers ─────────────────────────────────────────────
|
# ── Subcommand handlers ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -288,11 +288,15 @@ def create_app(bot_token: str, signing_secret: str, schedule_channel: str | None
|
||||||
if is_today(date_str):
|
if is_today(date_str):
|
||||||
invoke_3cx_scheduler(employee["extension"])
|
invoke_3cx_scheduler(employee["extension"])
|
||||||
|
|
||||||
|
respond(text=f"You picked up the shift for *{date.strftime('%A, %b %-d')}*.")
|
||||||
|
|
||||||
blocks = build_shift_change_message(
|
blocks = build_shift_change_message(
|
||||||
user_id, date_str, "picked_up", employee["extension"], employee["name"]
|
user_id, date_str, "picked_up", employee["extension"], employee["name"]
|
||||||
)
|
)
|
||||||
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift picked up for {date_str}")
|
try:
|
||||||
respond(text=f"You picked up the shift for *{date.strftime('%A, %b %-d')}*.")
|
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift picked up for {date_str}")
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to post pickup notification to channel")
|
||||||
|
|
||||||
def _handle_drop(respond, schedule, user_id, text, channel_id, client):
|
def _handle_drop(respond, schedule, user_id, text, channel_id, client):
|
||||||
parts = text.split(maxsplit=1)
|
parts = text.split(maxsplit=1)
|
||||||
|
|
@ -323,10 +327,14 @@ def create_app(bot_token: str, signing_secret: str, schedule_channel: str | None
|
||||||
if is_today(date_str):
|
if is_today(date_str):
|
||||||
invoke_3cx_scheduler(FALLBACK_EXTENSION)
|
invoke_3cx_scheduler(FALLBACK_EXTENSION)
|
||||||
|
|
||||||
blocks = build_shift_change_message(user_id, date_str, "dropped", ext, name)
|
|
||||||
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift dropped for {date_str}")
|
|
||||||
respond(text=f"You dropped the shift for *{date.strftime('%A, %b %-d')}*. It's now open for pickup.")
|
respond(text=f"You dropped the shift for *{date.strftime('%A, %b %-d')}*. It's now open for pickup.")
|
||||||
|
|
||||||
|
blocks = build_shift_change_message(user_id, date_str, "dropped", ext, name)
|
||||||
|
try:
|
||||||
|
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift dropped for {date_str}")
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to post drop notification to channel")
|
||||||
|
|
||||||
def _handle_swap(respond, schedule, user_id, text, channel_id, client):
|
def _handle_swap(respond, schedule, user_id, text, channel_id, client):
|
||||||
# Expected format: swap <date> @user OR swap <date> <extension>
|
# Expected format: swap <date> @user OR swap <date> <extension>
|
||||||
parts = text.split(maxsplit=2)
|
parts = text.split(maxsplit=2)
|
||||||
|
|
@ -379,7 +387,11 @@ def create_app(bot_token: str, signing_secret: str, schedule_channel: str | None
|
||||||
target["extension"],
|
target["extension"],
|
||||||
target["name"],
|
target["name"],
|
||||||
)
|
)
|
||||||
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift swapped for {date_str}")
|
|
||||||
respond(text=f"Swapped *{date.strftime('%A, %b %-d')}* to {target['name']} (Ext {target['extension']}).")
|
respond(text=f"Swapped *{date.strftime('%A, %b %-d')}* to {target['name']} (Ext {target['extension']}).")
|
||||||
|
|
||||||
|
try:
|
||||||
|
client.chat_postMessage(channel=channel_id, blocks=blocks, text=f"Shift swapped for {date_str}")
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to post swap notification to channel")
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
||||||
|
|
@ -74,9 +74,10 @@ class ShiftSchedule:
|
||||||
)
|
)
|
||||||
|
|
||||||
def claim_open_shift(self, date_str: str, extension: str, name: str, shift_type: str = "night") -> bool:
|
def claim_open_shift(self, date_str: str, extension: str, name: str, shift_type: str = "night") -> bool:
|
||||||
"""Atomically claim a shift only if it is currently OPEN.
|
"""Atomically claim a shift only if it is currently open.
|
||||||
|
|
||||||
Returns True if the claim succeeded, False if someone else already took it.
|
Succeeds when no override exists (weekly fallback) or the override
|
||||||
|
is explicitly OPEN. Fails if someone else already claimed it.
|
||||||
"""
|
"""
|
||||||
sk = f"{date_str}-DAY" if shift_type == "day" else date_str
|
sk = f"{date_str}-DAY" if shift_type == "day" else date_str
|
||||||
try:
|
try:
|
||||||
|
|
@ -87,7 +88,7 @@ class ShiftSchedule:
|
||||||
"extension": extension,
|
"extension": extension,
|
||||||
"name": name,
|
"name": name,
|
||||||
},
|
},
|
||||||
ConditionExpression="extension = :open",
|
ConditionExpression="attribute_not_exists(PK) OR extension = :open",
|
||||||
ExpressionAttributeValues={":open": "OPEN"},
|
ExpressionAttributeValues={":open": "OPEN"},
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue