# retoor <retoor@molodetz.nl>
from devplacepy.database import CONSENTS_TABLE, db, get_setting, get_table
from .agreements import Agreement
DEFAULT_VERSION = "1"
LIVE_ACCOUNT_CLAUSES: tuple[tuple[str, str], ...] = (
("deletion_requested_at", "COALESCE(u.deletion_requested_at, '') = ''"),
("is_active", "COALESCE(u.is_active, 1) != 0"),
("deleted_at", "u.deleted_at IS NULL"),
)
def latest_consent(column: str, user_ref: str) -> str:
return (
f"COALESCE((SELECT c.{column} FROM {CONSENTS_TABLE} c "
f"WHERE c.owner_kind = 'user' AND c.owner_id = {user_ref} "
"AND c.kind = :kind AND c.deleted_at IS NULL "
"ORDER BY c.created_at DESC, c.id DESC LIMIT 1), '')"
)
def not_withdrawn(user_ref: str) -> str:
return f"{latest_consent('state', user_ref)} != 'withdrawn'"
def has_gate_column(agreement: Agreement) -> bool:
if not agreement.gate_column:
return False
if "users" not in db.tables:
return False
return get_table("users").has_column(agreement.gate_column)
def satisfied_clause(agreement: Agreement, user_ref: str, column_prefix: str) -> str:
if has_gate_column(agreement):
return f"COALESCE({column_prefix}{agreement.gate_column}, '') != :version"
if agreement.version_setting:
return f"{latest_consent('version', user_ref)} != :version"
return f"{latest_consent('state', user_ref)} != 'granted'"
def live_account_clauses() -> list[str]:
users = get_table("users")
return [
clause for column, clause in LIVE_ACCOUNT_CLAUSES if users.has_column(column)
]
def current_version(agreement: Agreement) -> str:
if not agreement.version_setting:
return DEFAULT_VERSION
return get_setting(agreement.version_setting, DEFAULT_VERSION) or DEFAULT_VERSION
def pending(agreement: Agreement, limit: int) -> list[dict]:
if "users" not in db.tables or CONSENTS_TABLE not in db.tables:
return []
bound = max(1, int(limit))
clauses = [
*live_account_clauses(),
not_withdrawn("u.uid"),
satisfied_clause(agreement, "u.uid", "u."),
]
sql = (
"SELECT u.uid, u.username FROM users u "
f"WHERE {' AND '.join(clauses)} "
"ORDER BY u.id LIMIT :limit"
)
rows = db.query(
sql,
kind=agreement.kind,
version=current_version(agreement),
limit=bound,
)
return [dict(row) for row in rows]