| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- #!/usr/bin/env python3
- """Patch wifi_key, wifi_ssid, and/or door_code on a reservation that contains a given date.
- Usage:
- uv run python3 scripts/patch_reservation_codes.py 2026-07-05 --wifi stone-angel-market --door 0472
- uv run python3 scripts/patch_reservation_codes.py 2026-07-05 --wifi new-word-combo --ssid MyNetwork
- uv run python3 scripts/patch_reservation_codes.py 2026-07-05 --door 1234
- """
- import argparse
- import asyncio
- import json
- import sys
- from datetime import date, datetime, timedelta
- from room_cal.store import DEFAULT_CALENDAR_NAME, get_backend
- from room_cal._utils import safe_json_loads, filter_events, service_name
- _PREFIX = 'Guest: '
- def _build_description(xd: dict, wk: str, ws: str | None, dc: str) -> str:
- svc = xd.get('service', '')
- wifi_line = f"WiFi: {ws} / {wk}" if ws else f"WiFi: {wk}"
- return (
- f"Name: {xd.get('guest_name', '')}\n"
- f"Service: {service_name(svc)}\n"
- f"Reservation ID: {xd.get('reservation_id', '')}\n"
- f"Door: {dc}\n"
- f"{wifi_line}"
- )
- async def patch(target: date, new_wifi: str | None, new_ssid: str | None, new_door: str | None, calendar_name: str) -> None:
- backend = get_backend(calendar_name)
- start = datetime(target.year, target.month, target.day)
- end = start + timedelta(days=1)
- records = await backend.fetch_range(start, end)
- reservations = filter_events(records, _PREFIX, all_day=False)
- if not reservations:
- print(f"No reservation found overlapping {target}", file=sys.stderr)
- sys.exit(1)
- if len(reservations) > 1:
- reservations.sort(key=lambda e: e.start)
- event = reservations[-1]
- print(f"Multiple reservations overlap {target}, using the later one ({event.start.date()} – {event.end.date()})")
- else:
- event = reservations[0]
- xd = safe_json_loads(event.x_data) or {}
- old_wifi = xd.get('wifi_key', '(none)')
- old_ssid = xd.get('wifi_ssid')
- old_door = xd.get('door_code', '(none)')
- wk = new_wifi if new_wifi is not None else old_wifi
- ws = new_ssid if new_ssid is not None else old_ssid
- dc = new_door if new_door is not None else old_door
- print(f"Reservation: {event.title} ({event.start.date()} – {event.end.date()})")
- if new_wifi is not None:
- print(f" wifi_key: {old_wifi!r} → {wk!r}")
- if new_ssid is not None:
- print(f" wifi_ssid: {old_ssid!r} → {ws!r}")
- if new_door is not None:
- print(f" door_code: {old_door!r} → {dc!r}")
- confirm = input("Apply? [y/N] ").strip().lower()
- if confirm != 'y':
- print("Aborted.")
- return
- xd['wifi_key'] = wk
- xd['wifi_ssid'] = ws
- xd['door_code'] = dc
- new_x_data = json.dumps(xd)
- new_description = _build_description(xd, wk, ws, dc)
- await backend.update(event.uid, description=new_description, x_data=new_x_data)
- print("Updated.")
- def main():
- parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
- parser.add_argument('date', type=date.fromisoformat, help='Any date within the reservation (YYYY-MM-DD)')
- parser.add_argument('--wifi', metavar='WIFI_KEY', help='New wifi_key string')
- parser.add_argument('--ssid', metavar='WIFI_SSID', help='New wifi_ssid string')
- parser.add_argument('--door', metavar='DOOR_CODE', help='New door_code string')
- parser.add_argument('--calendar', default=DEFAULT_CALENDAR_NAME, help=f'Calendar name (default: {DEFAULT_CALENDAR_NAME})')
- args = parser.parse_args()
- if args.wifi is None and args.ssid is None and args.door is None:
- parser.error('Provide at least one of --wifi, --ssid, or --door')
- asyncio.run(patch(args.date, args.wifi, args.ssid, args.door, args.calendar))
- if __name__ == '__main__':
- main()
|