From b67f3f5999da90182611d4b9deca30d5a360340a Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 18 Sep 2026 00:06:25 +0500 Subject: [PATCH] undated enforcement --- app/enforcement.py | 96 +++++++++++++++++++++++++++++++++++++++++----- config/state.json | 6 ++- config/users.yaml | 2 +- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/app/enforcement.py b/app/enforcement.py index c4d7f7c..470045d 100644 --- a/app/enforcement.py +++ b/app/enforcement.py @@ -553,8 +553,6 @@ def _clean_old_state() -> None: ] continue - # Keep recent history instead - # of deleting everything. dates = sorted( user_usage.keys() ) @@ -770,6 +768,86 @@ def evaluate_user( or allowed_by_grant ) + # --------------------------------------------------------- + # DAILY USAGE ACCOUNTING + # + # The scheduler runs once every second. + # + # Only count usage when: + # 1. The user is actually logged in. + # 2. The user is inside an allowed access window. + # 3. The user still has daily allowance remaining. + # + # Temporary grants are consumed separately below. + # --------------------------------------------------------- + if ( + logged_in + and inside_window + and allowance_remaining > 0 + ): + record_usage( + user_id, + 1, + ) + + # Refresh the usage value immediately so + # the returned policy information reflects + # the second we just consumed. + usage_seconds += 1 + + allowance_remaining = max( + 0, + allowance_seconds + - usage_seconds, + ) + + total_remaining = ( + allowance_remaining + + grant_seconds + ) + + # If this second consumed the final + # allowance second, the user must be + # locked during this same scheduler pass. + if allowance_remaining <= 0: + should_allow = ( + grant_seconds > 0 + ) + + # --------------------------------------------------------- + # TEMPORARY GRANT ACCOUNTING + # + # Temporary time is consumed only while the + # user is actually logged in and is being + # allowed by the temporary grant. + # + # The grant also has its own expires_at timestamp, + # so it cannot remain valid beyond its expiry. + # --------------------------------------------------------- + if ( + logged_in + and grant_seconds > 0 + ): + consume_grant_seconds( + user_id, + 1, + ) + + grant_seconds = max( + 0, + grant_seconds - 1, + ) + + total_remaining = ( + allowance_remaining + + grant_seconds + ) + + should_allow = ( + allowed_by_schedule + or grant_seconds > 0 + ) + try: locked = is_locked( username @@ -784,8 +862,6 @@ def evaluate_user( username ) - # Re-check the state after - # unlocking. if not is_locked( username ): @@ -795,9 +871,6 @@ def evaluate_user( with _state_lock: state = load_state() - # The enforcement loop must - # continue even if one account - # cannot be unlocked. _ = state _ = exc @@ -831,8 +904,13 @@ def evaluate_user( "allowance_remaining": allowance_remaining, "grant_seconds": grant_seconds, "total_remaining": total_remaining, - "allowed_by_schedule": allowed_by_schedule, - "allowed_by_grant": allowed_by_grant, + "allowed_by_schedule": ( + inside_window + and allowance_remaining > 0 + ), + "allowed_by_grant": ( + grant_seconds > 0 + ), "allowed": should_allow, } diff --git a/config/state.json b/config/state.json index fe21b13..4f8ede2 100644 --- a/config/state.json +++ b/config/state.json @@ -1,4 +1,8 @@ { - "usage": {}, + "usage": { + "testuser1": { + "2026-09-17": 636 + } + }, "temporary_grants": [] } \ No newline at end of file diff --git a/config/users.yaml b/config/users.yaml index 026a2f8..acb38db 100644 --- a/config/users.yaml +++ b/config/users.yaml @@ -7,7 +7,7 @@ users: monday: 0 tuesday: 0 wednesday: 0 - thursday: 600 + thursday: 900 friday: 0 saturday: 0 access_windows: