mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-10-01 07:13:11 +00:00
The pickup button handler used an unconditional put_item, so concurrent clicks would both succeed with last-write-wins. Added claim_open_shift() which uses a DynamoDB ConditionExpression to only write if the shift is still OPEN. The button handler now returns an ephemeral "already taken" message when the condition fails. Closes #19
This commit is contained in:
parent
fe6b780e12
commit
1e90e0eaa2
2 changed files with 29 additions and 2 deletions
10
src/app.py
10
src/app.py
|
|
@ -124,7 +124,6 @@ def create_app(bot_token: str, signing_secret: str) -> App:
|
|||
def handle_pickup_button(ack, body, client):
|
||||
ack()
|
||||
action_id = body["actions"][0]["action_id"]
|
||||
# Parse action_id: pickup_2026-04-12 or pickup_2026-04-12_day
|
||||
remainder = action_id.replace("pickup_", "")
|
||||
if remainder.endswith("_day"):
|
||||
date_str = remainder[:-4]
|
||||
|
|
@ -145,7 +144,14 @@ def create_app(bot_token: str, signing_secret: str) -> App:
|
|||
)
|
||||
return
|
||||
|
||||
schedule.set_override(date_str, employee["extension"], employee["name"], shift_type)
|
||||
claimed = schedule.claim_open_shift(date_str, employee["extension"], employee["name"], shift_type)
|
||||
if not claimed:
|
||||
client.chat_postEphemeral(
|
||||
channel=channel_id,
|
||||
user=user_id,
|
||||
text=f"That shift on *{date_str}* was already picked up by someone else.",
|
||||
)
|
||||
return
|
||||
|
||||
if is_today(date_str) and shift_type == "night":
|
||||
invoke_3cx_scheduler(employee["extension"])
|
||||
|
|
|
|||
|
|
@ -73,6 +73,27 @@ class ShiftSchedule:
|
|||
}
|
||||
)
|
||||
|
||||
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.
|
||||
|
||||
Returns True if the claim succeeded, False if someone else already took it.
|
||||
"""
|
||||
sk = f"{date_str}-DAY" if shift_type == "day" else date_str
|
||||
try:
|
||||
self.table.put_item(
|
||||
Item={
|
||||
"PK": "OVERRIDE",
|
||||
"SK": sk,
|
||||
"extension": extension,
|
||||
"name": name,
|
||||
},
|
||||
ConditionExpression="extension = :open",
|
||||
ExpressionAttributeValues={":open": "OPEN"},
|
||||
)
|
||||
return True
|
||||
except self.table.meta.client.exceptions.ConditionalCheckFailedException:
|
||||
return False
|
||||
|
||||
def mark_open(self, date_str: str, shift_type: str = "night") -> None:
|
||||
sk = f"{date_str}-DAY" if shift_type == "day" else date_str
|
||||
self.table.put_item(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue