From 6d83d39ac2bae3dab6a94fbc56022dd3331d6c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Marschollek?= Date: Mon, 29 Nov 2021 00:09:06 +0100 Subject: [PATCH] Support `--latest-day` Allows users to specify the latest acceptable date for an appointment. By using `--earliest-day` and `--latest-day`, we can now specify an exact time range for the appointment. --- CHANGELOG.md | 11 +++++++++++ README.md | 6 ++++-- impf.py | 41 +++++++++++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e9337be --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# v1.0.2 + +- Added support for the `--latest-day` option + +# v1.0.1 + +- Fixed a bug where the `--earliest-day` option wasn't optional, but should have been + +# v1.0.0 + +- Initial release diff --git a/README.md b/README.md index 5a8875a..823dad3 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ python impf.py --citizen-id=AAAAAAAA-0000-0000-0000-AAAAAAAAAAAA --email=user@ex Full help: ``` $ python impf.py -h Py byImpf 14:25:01 -usage: impf.py [-h] --citizen-id CITIZEN_ID --email EMAIL --password PASSWORD [--earliest-day EARLIEST_DAY] [--interval INTERVAL] [--book | --no-book] +usage: impf.py [-h] --citizen-id CITIZEN_ID --email EMAIL --password PASSWORD [--earliest-day EARLIEST_DAY] [--latest-day LATEST_DAY] [--interval INTERVAL] [--book | --no-book] Appointment checker and booker for Bavarian vaccination centres @@ -49,7 +49,9 @@ optional arguments: --password PASSWORD Your login password --earliest-day EARLIEST_DAY The earliest day from which to find an appointment, in ISO format (YYYY-MM-DD) - --interval INTERVAL The interval in seconds between checks for appointments. If not passed, only one attempt is made. + --latest-day LATEST_DAY + The latest acceptable day for an appointment, in ISO format (YYYY-MM-DD) + --interval INTERVAL The interval in seconds between checks. If not passed, only one check is made. --book, --no-book Whether to book the appointment if found (default: False) ``` diff --git a/impf.py b/impf.py index 5c2d8b2..299543d 100644 --- a/impf.py +++ b/impf.py @@ -211,7 +211,9 @@ def _appointments_url(self, resource: Optional[str] = None): resource if resource is not None else "" ) - def _find_appointment(self, earliest_day) -> Optional[Dict]: + def _find_appointment( + self, earliest_day, latest_day: Optional[date] + ) -> Optional[Dict]: """ Finds an appointment in the user's vaccination centre @@ -241,13 +243,29 @@ def _find_appointment(self, earliest_day) -> Optional[Dict]: self.reset_session() return None - return appt_rsp.json() + appt = appt_rsp.json() - def find(self, earliest_day: Optional[str] = None, *, book: bool = False) -> bool: + if ( + latest_day + and datetime.date.fromisoformat(appt["vaccinationDate"]) > latest_day + ): + # We found an appointment, but it's too far in the future + return None + + return appt + + def find( + self, + earliest_day: Optional[str] = None, + latest_day: Optional[str] = None, + *, + book: bool = False, + ) -> bool: """ Finds an appointment in the user's vaccination centre :param earliest_day: The earliest acceptable day in ISO format (YYYY-MM-DD) + :param latest_day: The latest acceptable day in ISO format (YYYY-MM-DD) :param book: Whether or not to book the appointment :return: False if no appointment found or booking failed. @@ -256,7 +274,7 @@ def find(self, earliest_day: Optional[str] = None, *, book: bool = False) -> boo if earliest_day is None: earliest_day = date.today() - appt = self._find_appointment(earliest_day.isoformat()) + appt = self._find_appointment(earliest_day.isoformat(), latest_day) if appt is None: logging.info("No appointment available") return False @@ -354,6 +372,11 @@ def main(): type=datetime.date.fromisoformat, help="The earliest day from which to find an appointment, in ISO format (YYYY-MM-DD)", ) + parser.add_argument( + "--latest-day", + type=datetime.date.fromisoformat, + help="The latest acceptable day for an appointment, in ISO format (YYYY-MM-DD)", + ) parser.add_argument( "--interval", type=int, @@ -380,10 +403,16 @@ def main(): ): with attempt: logging.debug("Trying to find appointment (attempt %d)", i) - if not checker.find(earliest_day=args.earliest_day, book=args.book): + if not checker.find( + earliest_day=args.earliest_day, + latest_day=args.latest_day, + book=args.book, + ): raise Exception("Unsuccessful attempt") else: - checker.find(earliest_day=args.earliest_day, book=args.book) + checker.find( + earliest_day=args.earliest_day, latest_day=args.latest_day, book=args.book + ) if args.book: checker.print_appointments()