feat: Phase 4 Batch 1 - enable enforcement for data entries
- Weight, Circumference, Caliper now BLOCK on limit exceeded - Raise HTTPException(403) with user-friendly message - Show used/limit and suggest contacting admin - Phase 2 → Phase 4 transition Phase 4: Enforcement (Batch 1/3) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
baad096ead
commit
cbcb6a2a34
|
|
@ -7,7 +7,7 @@ import uuid
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Header, Depends
|
from fastapi import APIRouter, Header, Depends, HTTPException
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from auth import require_auth, check_feature_access, increment_feature_usage
|
from auth import require_auth, check_feature_access, increment_feature_usage
|
||||||
|
|
@ -35,15 +35,20 @@ def upsert_caliper(e: CaliperEntry, x_profile_id: Optional[str]=Header(default=N
|
||||||
"""Create or update caliper entry (upsert by date)."""
|
"""Create or update caliper entry (upsert by date)."""
|
||||||
pid = get_pid(x_profile_id)
|
pid = get_pid(x_profile_id)
|
||||||
|
|
||||||
# Phase 2: Check feature access (non-blocking, log only)
|
# Phase 4: Check feature access and ENFORCE
|
||||||
access = check_feature_access(pid, 'caliper_entries')
|
access = check_feature_access(pid, 'caliper_entries')
|
||||||
log_feature_usage(pid, 'caliper_entries', access, 'create')
|
log_feature_usage(pid, 'caliper_entries', access, 'create')
|
||||||
|
|
||||||
if not access['allowed']:
|
if not access['allowed']:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"[FEATURE-LIMIT] User {pid} would be blocked: "
|
f"[FEATURE-LIMIT] User {pid} blocked: "
|
||||||
f"caliper_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
f"caliper_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
||||||
)
|
)
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail=f"Limit erreicht: Du hast das Kontingent für Caliper-Einträge überschritten ({access['used']}/{access['limit']}). "
|
||||||
|
f"Bitte kontaktiere den Admin oder warte bis zum nächsten Reset."
|
||||||
|
)
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import uuid
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Header, Depends
|
from fastapi import APIRouter, Header, Depends, HTTPException
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from auth import require_auth, check_feature_access, increment_feature_usage
|
from auth import require_auth, check_feature_access, increment_feature_usage
|
||||||
|
|
@ -35,15 +35,20 @@ def upsert_circ(e: CircumferenceEntry, x_profile_id: Optional[str]=Header(defaul
|
||||||
"""Create or update circumference entry (upsert by date)."""
|
"""Create or update circumference entry (upsert by date)."""
|
||||||
pid = get_pid(x_profile_id)
|
pid = get_pid(x_profile_id)
|
||||||
|
|
||||||
# Phase 2: Check feature access (non-blocking, log only)
|
# Phase 4: Check feature access and ENFORCE
|
||||||
access = check_feature_access(pid, 'circumference_entries')
|
access = check_feature_access(pid, 'circumference_entries')
|
||||||
log_feature_usage(pid, 'circumference_entries', access, 'create')
|
log_feature_usage(pid, 'circumference_entries', access, 'create')
|
||||||
|
|
||||||
if not access['allowed']:
|
if not access['allowed']:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"[FEATURE-LIMIT] User {pid} would be blocked: "
|
f"[FEATURE-LIMIT] User {pid} blocked: "
|
||||||
f"circumference_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
f"circumference_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
||||||
)
|
)
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail=f"Limit erreicht: Du hast das Kontingent für Umfangs-Einträge überschritten ({access['used']}/{access['limit']}). "
|
||||||
|
f"Bitte kontaktiere den Admin oder warte bis zum nächsten Reset."
|
||||||
|
)
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import uuid
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Header, Depends
|
from fastapi import APIRouter, Header, Depends, HTTPException
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from auth import require_auth, check_feature_access, increment_feature_usage
|
from auth import require_auth, check_feature_access, increment_feature_usage
|
||||||
|
|
@ -35,19 +35,23 @@ def upsert_weight(e: WeightEntry, x_profile_id: Optional[str]=Header(default=Non
|
||||||
"""Create or update weight entry (upsert by date)."""
|
"""Create or update weight entry (upsert by date)."""
|
||||||
pid = get_pid(x_profile_id)
|
pid = get_pid(x_profile_id)
|
||||||
|
|
||||||
# Phase 2: Check feature access (non-blocking, log only)
|
# Phase 4: Check feature access and ENFORCE
|
||||||
access = check_feature_access(pid, 'weight_entries')
|
access = check_feature_access(pid, 'weight_entries')
|
||||||
|
|
||||||
# Structured logging (always)
|
# Structured logging (always)
|
||||||
log_feature_usage(pid, 'weight_entries', access, 'create')
|
log_feature_usage(pid, 'weight_entries', access, 'create')
|
||||||
|
|
||||||
# Warning if limit exceeded (legacy)
|
# BLOCK if limit exceeded
|
||||||
if not access['allowed']:
|
if not access['allowed']:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"[FEATURE-LIMIT] User {pid} would be blocked: "
|
f"[FEATURE-LIMIT] User {pid} blocked: "
|
||||||
f"weight_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
f"weight_entries {access['reason']} (used: {access['used']}, limit: {access['limit']})"
|
||||||
)
|
)
|
||||||
# NOTE: Phase 2 does NOT block - just logs!
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail=f"Limit erreicht: Du hast das Kontingent für Gewichtseinträge überschritten ({access['used']}/{access['limit']}). "
|
||||||
|
f"Bitte kontaktiere den Admin oder warte bis zum nächsten Reset."
|
||||||
|
)
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user