From dc545f9ea457a6152fdc4d6a5a10ea3f535baa8f Mon Sep 17 00:00:00 2001 From: Gabriel Chan Date: Mon, 30 Oct 2023 15:30:31 +0800 Subject: [PATCH 1/5] change door-open's graceful period to 1 minute. --- hackman/templates/payment_submit.jinja2 | 2 ++ hackman_payments/api.py | 28 +++++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/hackman/templates/payment_submit.jinja2 b/hackman/templates/payment_submit.jinja2 index b5dd274..e59e7ed 100644 --- a/hackman/templates/payment_submit.jinja2 +++ b/hackman/templates/payment_submit.jinja2 @@ -42,6 +42,8 @@

It may take a couple of days for someone to manually collect your envelope and update the master database. +

You may open the door within the next 1 minute. +


  Back to space actions diff --git a/hackman_payments/api.py b/hackman_payments/api.py index 2894a9b..3935dd9 100644 --- a/hackman_payments/api.py +++ b/hackman_payments/api.py @@ -60,7 +60,8 @@ def has_paid(user_id: int) -> PaymentGrade: return PaymentGrade.NOT_PAID now = _get_now() - if valid_until < now and valid_until + timedelta(weeks=2) >= now: + + if is_within_grace_period(user_id): return PaymentGrade.GRACE elif valid_until >= now: @@ -69,6 +70,20 @@ def has_paid(user_id: int) -> PaymentGrade: else: return PaymentGrade.NOT_PAID +def is_within_grace_period(user_id: int) -> bool: + r = get_redis_connection("default") + user_claim_grace_at = r.get(f"user_claim_grace_{user_id}").decode('utf-8') + print(user_claim_grace_at) + try: + claim_at = datetime.strptime(user_claim_grace_at, "%Y-%m-%dT%H:%M:%S.%fZ") + print(claim_at, datetime.utcnow()) + if claim_at <= datetime.utcnow() and datetime.utcnow() <= claim_at + timedelta(minutes=1): + return True + else: + return False + except (TypeError, ValueError) as e: + print('warning: parse error for grace period for user', user_id, e) + return False def unpaid_users() -> Generator[User, None, None]: """Yield all user ids that have not paid in advance""" @@ -91,9 +106,10 @@ def payment_submit( user_id: int, year: int, month: int, _redis_pipe: typing.Any = None ) -> None: - valid_until = datetime(year, month, calendar.monthrange(year, month)[1], 23, 59) + if year == datetime.now().year and month == datetime.now().month: + r = _redis_pipe or get_redis_connection("default") + r.set(f"user_claim_grace_{user_id}", f"{datetime.utcnow().isoformat()}Z") + else: + pass + # supposedly I should log someone's payment-claim. - r = _redis_pipe or get_redis_connection("default") - r.set("payment_user_id_{}".format(user_id), valid_until.isoformat()) - # FIXME - we only know to month accuracy the payment details, so - # storing a full datetime is wrong From f7338b381d9c645838b44e82f1dd81d82b7716a1 Mon Sep 17 00:00:00 2001 From: Gabriel Chan Date: Tue, 31 Oct 2023 11:22:38 +0800 Subject: [PATCH 2/5] update README. --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index dbb9bdb..6c59d89 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ The intent is to have a documented process that depends only on the Raspberry Pi hardware and thus can be easily tested or trialed. That being said, there are several ways to speed up or otherwise improve on this in the future. +### The manual way (before pi-gen building image) 1. Start with a fresh raspian lite bullseye install image, with ssh enabled 1. Dont forget to change the passwords and set up any extra users on the pi 1. `sudo apt-get update && sudo apt-get -y upgrade` @@ -50,6 +51,18 @@ are several ways to speed up or otherwise improve on this in the future. 1. reboot to activate all changes 3. Never run anything manually again \o/ +### The (more) Continuous Integration way +1. GitHub Actions should build a new .zip RaspberryPi Image on every new commit on master branch. +1. dump database: `pg_dump -Ft postgresql://hackman:hackman@localhost/hackman > /tmp/hackman_dump_.tar` +1. dump `~/.ssh/authorized_keys` +1. create new database, user, and grant privileges: + * `sudo -u postgres psql` + * `create database hackman;` + * `create user hackman with encrypted password ‘hackman’;` + * `grant all privileges on database hackman to hackman;` +1. load database: `pg_restore -v -d postgresql://hackman:hackman@localhost/hackman /tmp/hackman_dump_.tar` +1. load `~/.ssh/authorized_keys` + ## Upgrades 1. This auto-updates from the latest Github release automatically. 1. If that were to fail you can manually install the updated deb. From 111cd1691ae90e0d007d9acacea20d5ec921c178 Mon Sep 17 00:00:00 2001 From: Gabriel Chan Date: Tue, 31 Oct 2023 14:41:12 +0800 Subject: [PATCH 3/5] fix python black check to pass CI test. --- hackman_payments/api.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hackman_payments/api.py b/hackman_payments/api.py index 3935dd9..92be810 100644 --- a/hackman_payments/api.py +++ b/hackman_payments/api.py @@ -39,7 +39,6 @@ def get_valid_until(user_id: int) -> Optional[date]: def has_paid(user_id: int) -> PaymentGrade: - r = get_redis_connection("default") user_model = get_user_model() @@ -70,21 +69,25 @@ def has_paid(user_id: int) -> PaymentGrade: else: return PaymentGrade.NOT_PAID + def is_within_grace_period(user_id: int) -> bool: r = get_redis_connection("default") - user_claim_grace_at = r.get(f"user_claim_grace_{user_id}").decode('utf-8') + user_claim_grace_at = r.get(f"user_claim_grace_{user_id}").decode("utf-8") print(user_claim_grace_at) try: claim_at = datetime.strptime(user_claim_grace_at, "%Y-%m-%dT%H:%M:%S.%fZ") print(claim_at, datetime.utcnow()) - if claim_at <= datetime.utcnow() and datetime.utcnow() <= claim_at + timedelta(minutes=1): + if claim_at <= datetime.utcnow() and datetime.utcnow() <= claim_at + timedelta( + minutes=1 + ): return True else: return False except (TypeError, ValueError) as e: - print('warning: parse error for grace period for user', user_id, e) + print("warning: parse error for grace period for user", user_id, e) return False + def unpaid_users() -> Generator[User, None, None]: """Yield all user ids that have not paid in advance""" @@ -105,11 +108,9 @@ def payment_reminder_email_format() -> str: def payment_submit( user_id: int, year: int, month: int, _redis_pipe: typing.Any = None ) -> None: - if year == datetime.now().year and month == datetime.now().month: r = _redis_pipe or get_redis_connection("default") r.set(f"user_claim_grace_{user_id}", f"{datetime.utcnow().isoformat()}Z") else: pass # supposedly I should log someone's payment-claim. - From b396358df4d2030610e77b1e86ab7c7fc1a32297 Mon Sep 17 00:00:00 2001 From: Gabriel Chan Date: Tue, 7 Nov 2023 21:07:31 +0800 Subject: [PATCH 4/5] fix the failed tests. --- hackman/views.py | 2 +- hackman_payments/api.py | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/hackman/views.py b/hackman/views.py index c4ab2c8..3dd2bb5 100644 --- a/hackman/views.py +++ b/hackman/views.py @@ -249,7 +249,7 @@ def payment_submit(request: HttpRequest, r: bool = False) -> HttpResponse: return http.HttpResponseBadRequest("Form error") year, month = form.cleaned_data["year_month"] - payment_api.payment_submit(user_id, year, month) + payment_api.payment_claim(user_id, year, month) notification_api.notify_subject( b"door_event", diff --git a/hackman_payments/api.py b/hackman_payments/api.py index 92be810..654a866 100644 --- a/hackman_payments/api.py +++ b/hackman_payments/api.py @@ -39,6 +39,10 @@ def get_valid_until(user_id: int) -> Optional[date]: def has_paid(user_id: int) -> PaymentGrade: + + if is_within_grace_period(user_id): + return PaymentGrade.GRACE + r = get_redis_connection("default") user_model = get_user_model() @@ -59,8 +63,7 @@ def has_paid(user_id: int) -> PaymentGrade: return PaymentGrade.NOT_PAID now = _get_now() - - if is_within_grace_period(user_id): + if valid_until < now and valid_until + timedelta(weeks=2) >= now: return PaymentGrade.GRACE elif valid_until >= now: @@ -72,8 +75,12 @@ def has_paid(user_id: int) -> PaymentGrade: def is_within_grace_period(user_id: int) -> bool: r = get_redis_connection("default") - user_claim_grace_at = r.get(f"user_claim_grace_{user_id}").decode("utf-8") - print(user_claim_grace_at) + user_claim_grace_at = r.get(f"user_claim_grace_{user_id}") + + if not user_claim_grace_at: + return False + + user_claim_grace_at = user_claim_grace_at.decode("utf-8") try: claim_at = datetime.strptime(user_claim_grace_at, "%Y-%m-%dT%H:%M:%S.%fZ") print(claim_at, datetime.utcnow()) @@ -108,6 +115,17 @@ def payment_reminder_email_format() -> str: def payment_submit( user_id: int, year: int, month: int, _redis_pipe: typing.Any = None ) -> None: + + valid_until = datetime(year, month, calendar.monthrange(year, month)[1], 23, 59) + + r = _redis_pipe or get_redis_connection("default") + r.set("payment_user_id_{}".format(user_id), valid_until.isoformat()) + # FIXME - we only know to month accuracy the payment details, so + # storing a full datetime is wrong + +def payment_claim( + user_id: int, year: int, month: int, _redis_pipe: typing.Any = None +) -> None: if year == datetime.now().year and month == datetime.now().month: r = _redis_pipe or get_redis_connection("default") r.set(f"user_claim_grace_{user_id}", f"{datetime.utcnow().isoformat()}Z") From 619f28835fcbd5576040d131d9773cb6ce3313d3 Mon Sep 17 00:00:00 2001 From: Gabriel Chan Date: Tue, 7 Nov 2023 21:10:26 +0800 Subject: [PATCH 5/5] black was complaining again on formatting. fixed. --- hackman_payments/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hackman_payments/api.py b/hackman_payments/api.py index 654a866..119faf7 100644 --- a/hackman_payments/api.py +++ b/hackman_payments/api.py @@ -123,6 +123,7 @@ def payment_submit( # FIXME - we only know to month accuracy the payment details, so # storing a full datetime is wrong + def payment_claim( user_id: int, year: int, month: int, _redis_pipe: typing.Any = None ) -> None: