Add power-user email allowlist to bypass demo turn cap

Trusted testers listed in AIDND_POWER_USERS get unmetered turns on the
shared demo key: demo_turns_left reports the full cap and count_demo_turn
skips them. Registered accounts only, matched case-insensitively.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
This commit is contained in:
parththakkar106
2026-07-21 00:21:30 +05:30
co-authored by Claude Opus 4.8
parent 36413acd3e
commit 94db6e055b
2 changed files with 23 additions and 0 deletions
+4
View File
@@ -59,6 +59,10 @@ AIDND_DEMO_ENDPOINT_URL=
AIDND_DEMO_MODELS= AIDND_DEMO_MODELS=
# Successful AI turns per user per day on the demo key. Default: 20 # Successful AI turns per user per day on the demo key. Default: 20
AIDND_DEMO_TURNS_PER_DAY= AIDND_DEMO_TURNS_PER_DAY=
# Comma-separated emails of "power users" (trusted testers) who bypass the daily
# demo cap entirely — unmetered turns on the shared demo key. Registered accounts
# only (guests have no email). Matched case-insensitively.
AIDND_POWER_USERS=
# The AI endpoint/API key/model are NOT env vars — they are configured at # The AI endpoint/API key/model are NOT env vars — they are configured at
# runtime in the app's Settings page and stored (encrypted) in the database. # runtime in the app's Settings page and stored (encrypted) in the database.
+19
View File
@@ -58,6 +58,14 @@ DEMO_MODELS = [
] or ["google/gemma-4-26b-a4b-it:free"] ] or ["google/gemma-4-26b-a4b-it:free"]
DEMO_TURNS_PER_DAY = int(os.environ.get("AIDND_DEMO_TURNS_PER_DAY", "20") or 20) DEMO_TURNS_PER_DAY = int(os.environ.get("AIDND_DEMO_TURNS_PER_DAY", "20") or 20)
# Trusted testers (by email) who bypass the daily demo cap — unmetered turns on
# the shared demo key. Comma-separated emails; matched case-insensitively.
POWER_USERS = {
e.strip().lower()
for e in os.environ.get("AIDND_POWER_USERS", "").split(",")
if e.strip()
}
DEMO_CAP_MESSAGE = ( DEMO_CAP_MESSAGE = (
f"You've used all {DEMO_TURNS_PER_DAY} free demo turns for today. " f"You've used all {DEMO_TURNS_PER_DAY} free demo turns for today. "
"Add your own API key in Settings to keep playing (it resets tomorrow)." "Add your own API key in Settings to keep playing (it resets tomorrow)."
@@ -93,13 +101,24 @@ def _today() -> str:
return models.utcnow().date().isoformat() return models.utcnow().date().isoformat()
def is_power_user(user: models.User) -> bool:
"""Trusted testers (email allowlist) bypass the demo turn cap."""
return bool(user.email) and user.email.lower() in POWER_USERS
def demo_turns_left(user: models.User) -> int: def demo_turns_left(user: models.User) -> int:
# Power users are never capped; report the full cap so the banner reads
# "N of N" rather than a decrementing count.
if is_power_user(user):
return DEMO_TURNS_PER_DAY
used = user.demo_turns_used if user.demo_turns_date == _today() else 0 used = user.demo_turns_used if user.demo_turns_date == _today() else 0
return max(0, DEMO_TURNS_PER_DAY - used) return max(0, DEMO_TURNS_PER_DAY - used)
def count_demo_turn(user: models.User) -> None: def count_demo_turn(user: models.User) -> None:
"""Record one demo turn; the caller's commit persists it.""" """Record one demo turn; the caller's commit persists it."""
if is_power_user(user):
return # unmetered — power users don't count against the cap
today = _today() today = _today()
if user.demo_turns_date != today: if user.demo_turns_date != today:
user.demo_turns_date = today user.demo_turns_date = today