perf: batch authorization and activity updates

This commit is contained in:
2026-07-29 14:16:28 +02:00
parent 3df4fc5bff
commit 984a015704
9 changed files with 613 additions and 85 deletions

View File

@@ -1,9 +1,9 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from govoplan_access.backend.auth.tokens import generate_secret, hash_secret, verify_secret
from govoplan_access.backend.db.models import ApiKey, User
@@ -60,17 +60,36 @@ def create_api_key(
return CreatedApiKey(model=model, secret=secret)
def authenticate_api_key(session: Session, secret: str) -> ApiKey | None:
def authenticate_api_key(
session: Session,
secret: str,
*,
touch_interval_seconds: int = 5 * 60,
) -> ApiKey | None:
prefix = api_key_prefix(secret)
candidates = session.query(ApiKey).filter(ApiKey.prefix == prefix, ApiKey.revoked_at.is_(None)).all()
candidates = (
session.query(ApiKey)
.options(joinedload(ApiKey.user).joinedload(User.account))
.filter(
ApiKey.prefix == prefix,
ApiKey.revoked_at.is_(None),
)
.all()
)
now = utc_now()
for candidate in candidates:
expires_at = ensure_aware_utc(candidate.expires_at)
if expires_at and expires_at < now:
continue
if verify_api_key(secret, candidate.key_hash):
candidate.last_used_at = now
session.add(candidate)
last_used_at = ensure_aware_utc(candidate.last_used_at)
if (
touch_interval_seconds <= 0
or last_used_at is None
or now - last_used_at >= timedelta(seconds=touch_interval_seconds)
):
candidate.last_used_at = now
session.add(candidate)
return candidate
return None
@@ -78,4 +97,3 @@ def authenticate_api_key(session: Session, secret: str) -> ApiKey | None:
def has_scope(api_key: ApiKey, required_scope: str) -> bool:
scopes = set(api_key.scopes or [])
return "*" in scopes or required_scope in scopes