Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
|
||||
from app.core.database import session_scope
|
||||
from app.modules.auth.models import EmailVerificationToken, PasswordResetToken, RefreshToken
|
||||
|
||||
|
||||
def _detach(db, instance):
|
||||
db.refresh(instance)
|
||||
db.expunge(instance)
|
||||
return instance
|
||||
|
||||
|
||||
def create_refresh_token(
|
||||
user_id: str,
|
||||
token_hash: str,
|
||||
family_id: str,
|
||||
expires_at: datetime,
|
||||
) -> RefreshToken:
|
||||
with session_scope() as db:
|
||||
token = RefreshToken(
|
||||
user_id=user_id,
|
||||
token_hash=token_hash,
|
||||
family_id=family_id,
|
||||
expires_at=expires_at,
|
||||
)
|
||||
db.add(token)
|
||||
db.flush()
|
||||
return _detach(db, token)
|
||||
|
||||
|
||||
def get_refresh_token(token_hash: str) -> RefreshToken | None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(select(RefreshToken).where(RefreshToken.token_hash == token_hash))
|
||||
if not token:
|
||||
return None
|
||||
return _detach(db, token)
|
||||
|
||||
|
||||
def revoke_refresh_token(token_hash: str) -> RefreshToken | None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(select(RefreshToken).where(RefreshToken.token_hash == token_hash))
|
||||
if not token:
|
||||
return None
|
||||
token.revoked_at = datetime.now(UTC)
|
||||
db.flush()
|
||||
return _detach(db, token)
|
||||
|
||||
|
||||
def revoke_user_families(user_id: str) -> None:
|
||||
with session_scope() as db:
|
||||
tokens = db.scalars(
|
||||
select(RefreshToken).where(
|
||||
RefreshToken.user_id == user_id,
|
||||
RefreshToken.revoked_at.is_(None),
|
||||
)
|
||||
).all()
|
||||
now = datetime.now(UTC)
|
||||
for token in tokens:
|
||||
token.revoked_at = now
|
||||
|
||||
|
||||
def revoke_family_tokens(family_id: str) -> None:
|
||||
with session_scope() as db:
|
||||
tokens = db.scalars(
|
||||
select(RefreshToken).where(
|
||||
RefreshToken.family_id == family_id,
|
||||
RefreshToken.revoked_at.is_(None),
|
||||
)
|
||||
).all()
|
||||
now = datetime.now(UTC)
|
||||
for token in tokens:
|
||||
token.revoked_at = now
|
||||
|
||||
|
||||
def create_email_verification_token(user_id: str, token_hash: str, expires_at: datetime) -> None:
|
||||
with session_scope() as db:
|
||||
db.execute(
|
||||
delete(EmailVerificationToken).where(
|
||||
EmailVerificationToken.user_id == user_id,
|
||||
EmailVerificationToken.used_at.is_(None),
|
||||
)
|
||||
)
|
||||
db.add(EmailVerificationToken(user_id=user_id, token_hash=token_hash, expires_at=expires_at))
|
||||
|
||||
|
||||
def get_email_verification_token(token_hash: str) -> EmailVerificationToken | None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(
|
||||
select(EmailVerificationToken).where(EmailVerificationToken.token_hash == token_hash)
|
||||
)
|
||||
if not token:
|
||||
return None
|
||||
return _detach(db, token)
|
||||
|
||||
|
||||
def mark_email_verification_token_used(token_hash: str) -> None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(
|
||||
select(EmailVerificationToken).where(EmailVerificationToken.token_hash == token_hash)
|
||||
)
|
||||
if token:
|
||||
token.used_at = datetime.now(UTC)
|
||||
|
||||
|
||||
def create_password_reset_token(user_id: str, token_hash: str, expires_at: datetime) -> None:
|
||||
with session_scope() as db:
|
||||
db.execute(
|
||||
delete(PasswordResetToken).where(
|
||||
PasswordResetToken.user_id == user_id,
|
||||
PasswordResetToken.used_at.is_(None),
|
||||
)
|
||||
)
|
||||
db.add(PasswordResetToken(user_id=user_id, token_hash=token_hash, expires_at=expires_at))
|
||||
|
||||
|
||||
def get_password_reset_token(token_hash: str) -> PasswordResetToken | None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(select(PasswordResetToken).where(PasswordResetToken.token_hash == token_hash))
|
||||
if not token:
|
||||
return None
|
||||
return _detach(db, token)
|
||||
|
||||
|
||||
def mark_password_reset_token_used(token_hash: str) -> None:
|
||||
with session_scope() as db:
|
||||
token = db.scalar(select(PasswordResetToken).where(PasswordResetToken.token_hash == token_hash))
|
||||
if token:
|
||||
token.used_at = datetime.now(UTC)
|
||||
Reference in New Issue
Block a user