habulaj commited on
Commit
4971336
·
verified ·
1 Parent(s): 0272b27

Create approvals.py

Browse files
Files changed (1) hide show
  1. routes/approvals.py +109 -0
routes/approvals.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import aiohttp
4
+ import asyncio
5
+ from fastapi import APIRouter, HTTPException, Header, Query
6
+ from typing import Dict, Any
7
+
8
+ router = APIRouter()
9
+
10
+ # Configuração do Supabase
11
+ SUPABASE_URL = "https://ussxqnifefkgkaumjann.supabase.co"
12
+ SUPABASE_KEY = os.getenv("SUPA_KEY")
13
+
14
+ if not SUPABASE_KEY:
15
+ raise ValueError("❌ SUPA_KEY não foi definido no ambiente!")
16
+
17
+ SUPABASE_HEADERS = {
18
+ "apikey": SUPABASE_KEY,
19
+ "Authorization": f"Bearer {SUPABASE_KEY}",
20
+ "Content-Type": "application/json"
21
+ }
22
+
23
+ # Configuração do logging
24
+ logging.basicConfig(level=logging.INFO)
25
+ logger = logging.getLogger(__name__)
26
+
27
+ # Cache de admin
28
+ from functools import lru_cache
29
+ import requests
30
+
31
+ @lru_cache(maxsize=128)
32
+ def get_cached_admin_status(user_id: str) -> bool:
33
+ user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
34
+ response = requests.get(user_data_url, headers=SUPABASE_HEADERS)
35
+
36
+ if response.status_code != 200 or not response.json():
37
+ return False
38
+
39
+ user_info = response.json()[0]
40
+ return user_info.get("is_admin", False)
41
+
42
+ async def verify_admin_token(user_token: str) -> str:
43
+ headers = {
44
+ "Authorization": f"Bearer {user_token}",
45
+ "apikey": SUPABASE_KEY,
46
+ "Content-Type": "application/json"
47
+ }
48
+
49
+ async with aiohttp.ClientSession() as session:
50
+ async with session.get(f"{SUPABASE_URL}/auth/v1/user", headers=headers) as response:
51
+ if response.status != 200:
52
+ raise HTTPException(status_code=401, detail="Token inválido ou expirado")
53
+
54
+ user_data = await response.json()
55
+ user_id = user_data.get("id")
56
+ if not user_id:
57
+ raise HTTPException(status_code=400, detail="ID do usuário não encontrado")
58
+
59
+ is_admin = await asyncio.to_thread(get_cached_admin_status, user_id)
60
+
61
+ if not is_admin:
62
+ raise HTTPException(status_code=403, detail="Acesso negado: privilégios de administrador necessários")
63
+
64
+ return user_id
65
+
66
+ async def get_users_pending_approval() -> Dict[str, Any]:
67
+ """Obtém todos os usuários que ainda não foram aprovados mas completaram o onboarding"""
68
+ try:
69
+ query = (
70
+ f"{SUPABASE_URL}/rest/v1/User"
71
+ "?select=id,name,avatar,role,blurhash"
72
+ "&approved_account=eq.false"
73
+ "&finished_onboarding=eq.true"
74
+ "&finished_stripe_onboarding=eq.true"
75
+ "&or=(approval_reason.is.null,approval_reason.eq.)"
76
+ )
77
+
78
+ headers = SUPABASE_HEADERS.copy()
79
+ headers["Accept"] = "application/json; charset=utf-8"
80
+
81
+ async with aiohttp.ClientSession() as session:
82
+ async with session.get(query, headers=headers) as response:
83
+ if response.status != 200:
84
+ logger.error(f"❌ Erro ao buscar usuários pendentes de aprovação: {response.status}")
85
+ raise HTTPException(status_code=500, detail="Erro ao consultar o Supabase")
86
+
87
+ users = await response.json()
88
+ return {"users": users, "count": len(users)}
89
+
90
+ except Exception as e:
91
+ logger.error(f"❌ Erro ao buscar usuários pendentes: {str(e)}")
92
+ raise HTTPException(status_code=500, detail="Erro interno do servidor")
93
+
94
+ @router.get("/admin/pending-approvals")
95
+ async def pending_approvals_endpoint(
96
+ user_token: str = Header(None, alias="User-key")
97
+ ):
98
+ """
99
+ Endpoint para listar usuários que ainda não foram aprovados,
100
+ mas já finalizaram o onboarding e o Stripe.
101
+ """
102
+ try:
103
+ await verify_admin_token(user_token)
104
+ return await get_users_pending_approval()
105
+ except HTTPException as he:
106
+ raise he
107
+ except Exception as e:
108
+ logger.error(f"❌ Erro no endpoint de aprovações: {str(e)}")
109
+ raise HTTPException(status_code=500, detail=str(e))