From b63021c4492a1742b8fa65c39ec648f140e0748b Mon Sep 17 00:00:00 2001 From: stuppie Date: Mon, 21 Sep 2026 18:03:20 -0600 Subject: cashout request email flow and views --- jb/api/cashout_token.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 jb/api/cashout_token.py (limited to 'jb/api/cashout_token.py') diff --git a/jb/api/cashout_token.py b/jb/api/cashout_token.py new file mode 100644 index 0000000..274383c --- /dev/null +++ b/jb/api/cashout_token.py @@ -0,0 +1,43 @@ +import secrets + +from fastapi import HTTPException, status +from generalresearch.redis_helper import RedisConfig + +from jb.api.magic_token import MAGIC_TOKEN_TTL, redis_token_key +from jb.decorators import get_redis_config +from jb.models.wallet import PendingCashout + +CASHOUT_TOKEN_PREFIX = "wallet:cashout:" + + +def create_cashout_token( + cashout: PendingCashout, redis_config: RedisConfig | None = None +) -> str: + """Create a short-lived, single-use token bound to a cashout request.""" + if redis_config is None: + redis_config = get_redis_config() + + token = secrets.token_urlsafe(32) + redis_config.create_redis_client().set( + redis_token_key(token, CASHOUT_TOKEN_PREFIX), + cashout.model_dump_json(), + ex=MAGIC_TOKEN_TTL, + ) + return token + + +def consume_cashout_token( + token: str, redis_config: RedisConfig | None = None +) -> PendingCashout: + if redis_config is None: + redis_config = get_redis_config() + + raw_data = redis_config.create_redis_client().getdel( + redis_token_key(token, CASHOUT_TOKEN_PREFIX) + ) + if raw_data is None: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid or expired cashout confirmation token", + ) + return PendingCashout.model_validate_json(raw_data) -- cgit v1.2.3