Add schedule post live-update and old post deletion (#40, #41)

- Store schedule message timestamp in DynamoDB (SCHEDULE_POST record)
- Delete previous week's schedule post before posting the new one
- Live-update the schedule post via chat_update after any
  pick/drop/swap/button-pickup so it always reflects current state
This commit is contained in:
Adam Moussa 2026-05-12 15:46:14 -04:00
parent b137334c5b
commit 9dd7cbd0f8
3 changed files with 61 additions and 2 deletions

View file

@ -142,6 +142,26 @@ class ShiftSchedule:
return (FALLBACK_EXTENSION, "Available", "available")
# ── Schedule post tracking ───────────────────────────────────────────
def get_schedule_post(self, channel_id: str) -> dict | None:
resp = self.table.get_item(
Key={"PK": "SCHEDULE_POST", "SK": channel_id}
)
return resp.get("Item")
def save_schedule_post(
self, channel_id: str, message_ts: str, week_start: str
) -> None:
self.table.put_item(
Item={
"PK": "SCHEDULE_POST",
"SK": channel_id,
"message_ts": message_ts,
"week_start": week_start,
}
)
# ── Pay records ─────────────────────────────────────────────────────
def get_pay_record(self, week_key: str) -> dict | None:

View file

@ -185,6 +185,29 @@ def create_app(
blocks=blocks,
text=f"Shift picked up for {date_str}",
)
_refresh_schedule_post(client)
def _refresh_schedule_post(client):
"""Update the pinned schedule message in-place after a shift change."""
channel = schedule_channel
if not channel:
return
post = schedule.get_schedule_post(channel)
if not post or not post.get("message_ts"):
return
try:
blocks = build_week_schedule(schedule)
now = datetime.now(EASTERN)
this_monday = now - timedelta(days=now.weekday())
end_date = this_monday + timedelta(days=13)
client.chat_update(
channel=channel,
ts=post["message_ts"],
blocks=blocks,
text=f"After-Hours Schedule — {now.strftime('%b %-d')} to {end_date.strftime('%b %-d')}",
)
except Exception:
logger.warning("Could not update schedule post", exc_info=True)
# ── Subcommand handlers ─────────────────────────────────────────────
@ -350,6 +373,7 @@ def create_app(
)
except Exception:
logger.exception("Failed to post pickup notification to channel")
_refresh_schedule_post(client)
def _handle_drop(respond, schedule, user_id, text, channel_id, client):
parts = text.split(maxsplit=1)
@ -395,6 +419,7 @@ def create_app(
)
except Exception:
logger.exception("Failed to post drop notification to channel")
_refresh_schedule_post(client)
def _handle_swap(respond, schedule, user_id, text, channel_id, client):
# Expected format: swap <date> @user OR swap <date> <extension>
@ -466,5 +491,6 @@ def create_app(
)
except Exception:
logger.exception("Failed to post swap notification to channel")
_refresh_schedule_post(client)
return app

View file

@ -189,20 +189,33 @@ def handler(event, context):
# Email pay summary to payroll
_send_pay_email(week_label, pay_record)
# --- Delete previous week's schedule post ---
old_post = schedule.get_schedule_post(channel_id)
if old_post and old_post.get("message_ts"):
try:
slack.chat_delete(channel=channel_id, ts=old_post["message_ts"])
logger.info("Deleted previous schedule post %s", old_post["message_ts"])
except Exception:
logger.warning("Could not delete old schedule post", exc_info=True)
# --- Two-week schedule (always starts on Monday of this week) ---
this_monday = now - timedelta(days=now.weekday())
blocks = build_week_schedule(schedule, start_date=this_monday)
end_date = this_monday + timedelta(days=13)
slack.chat_postMessage(
result = slack.chat_postMessage(
channel=channel_id,
blocks=blocks,
text=f"After-Hours Schedule — {now.strftime('%b %-d')} to {end_date.strftime('%b %-d')}",
)
logger.info("Posted weekly schedule to channel %s", channel_id)
schedule.save_schedule_post(
channel_id, result["ts"], this_monday.strftime("%Y-%m-%d")
)
logger.info("Posted weekly schedule to channel %s (ts=%s)", channel_id, result["ts"])
return {
"posted": True,
"channel": channel_id,
"message_ts": result["ts"],
"pay_calculated": bool(pay_record["breakdown"]),
}