habulaj commited on
Commit
9143d03
·
verified ·
1 Parent(s): 7041568

Update routes/approvals.py

Browse files
Files changed (1) hide show
  1. routes/approvals.py +22 -31
routes/approvals.py CHANGED
@@ -11,6 +11,7 @@ from collections import defaultdict
11
 
12
  router = APIRouter()
13
 
 
14
  class ApproveAccountRequest(BaseModel):
15
  user_id: str
16
 
@@ -18,12 +19,13 @@ class RejectAccountRequest(BaseModel):
18
  user_id: str
19
  reason: Optional[str] = None
20
 
21
- # Configuração do Supabase
22
  SUPABASE_URL = "https://ussxqnifefkgkaumjann.supabase.co"
23
  SUPABASE_KEY = os.getenv("SUPA_KEY")
 
24
 
25
- if not SUPABASE_KEY:
26
- raise ValueError("❌ SUPA_KEY não foi definido no ambiente!")
27
 
28
  SUPABASE_HEADERS = {
29
  "apikey": SUPABASE_KEY,
@@ -31,11 +33,17 @@ SUPABASE_HEADERS = {
31
  "Content-Type": "application/json"
32
  }
33
 
34
- # Configuração do logging
 
 
 
 
 
 
35
  logging.basicConfig(level=logging.INFO)
36
  logger = logging.getLogger(__name__)
37
 
38
- # Cache de admin
39
  @lru_cache(maxsize=128)
40
  def get_cached_admin_status(user_id: str) -> bool:
41
  user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
@@ -47,6 +55,7 @@ def get_cached_admin_status(user_id: str) -> bool:
47
  user_info = response.json()[0]
48
  return user_info.get("is_admin", False)
49
 
 
50
  async def verify_admin_token(user_token: str) -> str:
51
  headers = {
52
  "Authorization": f"Bearer {user_token}",
@@ -71,8 +80,8 @@ async def verify_admin_token(user_token: str) -> str:
71
 
72
  return user_id
73
 
 
74
  async def get_users_pending_approval() -> Dict[str, Any]:
75
- """Obtém todos os usuários que ainda não foram aprovados e suas respostas de onboarding"""
76
  try:
77
  query_users = (
78
  f"{SUPABASE_URL}/rest/v1/User"
@@ -87,12 +96,10 @@ async def get_users_pending_approval() -> Dict[str, Any]:
87
  headers["Accept"] = "application/json; charset=utf-8"
88
 
89
  async with aiohttp.ClientSession() as session:
90
- # Busca os usuários pendentes
91
  async with session.get(query_users, headers=headers) as response:
92
  if response.status != 200:
93
  logger.error(f"❌ Erro ao buscar usuários pendentes: {response.status}")
94
  raise HTTPException(status_code=500, detail="Erro ao consultar usuários")
95
-
96
  users = await response.json()
97
 
98
  if not users:
@@ -101,7 +108,6 @@ async def get_users_pending_approval() -> Dict[str, Any]:
101
  user_ids = [user['id'] for user in users]
102
  user_ids_str = ",".join(user_ids)
103
 
104
- # Busca as respostas desses usuários
105
  query_answers = (
106
  f"{SUPABASE_URL}/rest/v1/User answers"
107
  f"?select=user_id,question_id,answers"
@@ -115,7 +121,6 @@ async def get_users_pending_approval() -> Dict[str, Any]:
115
  else:
116
  user_answers = await response.json()
117
 
118
- # Busca as perguntas
119
  query_questions = f"{SUPABASE_URL}/rest/v1/Onboarding?select=id,title"
120
  async with session.get(query_questions, headers=headers) as response:
121
  if response.status != 200:
@@ -124,10 +129,7 @@ async def get_users_pending_approval() -> Dict[str, Any]:
124
  else:
125
  questions = await response.json()
126
 
127
- # Mapeia perguntas por ID
128
  question_map = {q["id"]: q["title"] for q in questions}
129
-
130
- # Agrupa respostas por usuário
131
  grouped_answers = defaultdict(list)
132
 
133
  for answer in user_answers:
@@ -137,7 +139,6 @@ async def get_users_pending_approval() -> Dict[str, Any]:
137
  "answer": answer.get("answers", [])
138
  })
139
 
140
- # Enriquecer usuários com respostas
141
  for user in users:
142
  user["answers"] = grouped_answers.get(user["id"], [])
143
 
@@ -147,25 +148,20 @@ async def get_users_pending_approval() -> Dict[str, Any]:
147
  logger.error(f"❌ Erro ao buscar usuários e respostas: {str(e)}")
148
  raise HTTPException(status_code=500, detail="Erro interno do servidor")
149
 
150
-
151
  @router.post("/admin/approve-account")
152
  async def approve_account(
153
  body: ApproveAccountRequest,
154
  user_token: str = Header(None, alias="User-key")
155
  ):
156
- """
157
- Aprova a conta de um usuário.
158
- """
159
  try:
160
  await verify_admin_token(user_token)
161
 
162
  update_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{body.user_id}"
163
- payload = {
164
- "approved_account": True
165
- }
166
 
167
  async with aiohttp.ClientSession() as session:
168
- async with session.patch(update_url, headers=SUPABASE_HEADERS, json=payload) as response:
169
  if response.status != 204:
170
  logger.error(f"❌ Erro ao aprovar conta: {response.status}")
171
  raise HTTPException(status_code=500, detail="Erro ao aprovar a conta")
@@ -178,14 +174,12 @@ async def approve_account(
178
  logger.error(f"❌ Erro ao aprovar conta: {str(e)}")
179
  raise HTTPException(status_code=500, detail=str(e))
180
 
 
181
  @router.post("/admin/reject-account")
182
  async def reject_account(
183
  body: RejectAccountRequest,
184
  user_token: str = Header(None, alias="User-key")
185
  ):
186
- """
187
- Reprova a conta de um usuário, com motivo.
188
- """
189
  try:
190
  await verify_admin_token(user_token)
191
 
@@ -196,7 +190,7 @@ async def reject_account(
196
  }
197
 
198
  async with aiohttp.ClientSession() as session:
199
- async with session.patch(update_url, headers=SUPABASE_HEADERS, json=payload) as response:
200
  if response.status != 204:
201
  logger.error(f"❌ Erro ao reprovar conta: {response.status}")
202
  raise HTTPException(status_code=500, detail="Erro ao reprovar a conta")
@@ -209,14 +203,11 @@ async def reject_account(
209
  logger.error(f"❌ Erro ao reprovar conta: {str(e)}")
210
  raise HTTPException(status_code=500, detail=str(e))
211
 
 
212
  @router.get("/admin/pending-approvals")
213
  async def pending_approvals_endpoint(
214
  user_token: str = Header(None, alias="User-key")
215
  ):
216
- """
217
- Endpoint para listar usuários que ainda não foram aprovados,
218
- com respostas das perguntas de onboarding.
219
- """
220
  try:
221
  await verify_admin_token(user_token)
222
  return await get_users_pending_approval()
@@ -224,4 +215,4 @@ async def pending_approvals_endpoint(
224
  raise he
225
  except Exception as e:
226
  logger.error(f"❌ Erro no endpoint de aprovações: {str(e)}")
227
- raise HTTPException(status_code=500, detail=str(e))
 
11
 
12
  router = APIRouter()
13
 
14
+ # 📦 Models
15
  class ApproveAccountRequest(BaseModel):
16
  user_id: str
17
 
 
19
  user_id: str
20
  reason: Optional[str] = None
21
 
22
+ # 🔥 Supabase Configuração com Secrets
23
  SUPABASE_URL = "https://ussxqnifefkgkaumjann.supabase.co"
24
  SUPABASE_KEY = os.getenv("SUPA_KEY")
25
+ SUPABASE_ROLE_KEY = os.getenv("SUPA_SERVICE_KEY")
26
 
27
+ if not SUPABASE_KEY or not SUPABASE_ROLE_KEY:
28
+ raise ValueError("❌ SUPA_KEY ou SUPA_SERVICE_KEY não foram definidos no ambiente!")
29
 
30
  SUPABASE_HEADERS = {
31
  "apikey": SUPABASE_KEY,
 
33
  "Content-Type": "application/json"
34
  }
35
 
36
+ SUPABASE_ROLE_HEADERS = {
37
+ "apikey": SUPABASE_ROLE_KEY,
38
+ "Authorization": f"Bearer {SUPABASE_ROLE_KEY}",
39
+ "Content-Type": "application/json"
40
+ }
41
+
42
+ # ⚙️ Logging
43
  logging.basicConfig(level=logging.INFO)
44
  logger = logging.getLogger(__name__)
45
 
46
+ # 🔒 Cache de admin
47
  @lru_cache(maxsize=128)
48
  def get_cached_admin_status(user_id: str) -> bool:
49
  user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
 
55
  user_info = response.json()[0]
56
  return user_info.get("is_admin", False)
57
 
58
+ # 🔐 Verificação de token com permissões normais
59
  async def verify_admin_token(user_token: str) -> str:
60
  headers = {
61
  "Authorization": f"Bearer {user_token}",
 
80
 
81
  return user_id
82
 
83
+ # 📥 Buscar usuários pendentes com respostas
84
  async def get_users_pending_approval() -> Dict[str, Any]:
 
85
  try:
86
  query_users = (
87
  f"{SUPABASE_URL}/rest/v1/User"
 
96
  headers["Accept"] = "application/json; charset=utf-8"
97
 
98
  async with aiohttp.ClientSession() as session:
 
99
  async with session.get(query_users, headers=headers) as response:
100
  if response.status != 200:
101
  logger.error(f"❌ Erro ao buscar usuários pendentes: {response.status}")
102
  raise HTTPException(status_code=500, detail="Erro ao consultar usuários")
 
103
  users = await response.json()
104
 
105
  if not users:
 
108
  user_ids = [user['id'] for user in users]
109
  user_ids_str = ",".join(user_ids)
110
 
 
111
  query_answers = (
112
  f"{SUPABASE_URL}/rest/v1/User answers"
113
  f"?select=user_id,question_id,answers"
 
121
  else:
122
  user_answers = await response.json()
123
 
 
124
  query_questions = f"{SUPABASE_URL}/rest/v1/Onboarding?select=id,title"
125
  async with session.get(query_questions, headers=headers) as response:
126
  if response.status != 200:
 
129
  else:
130
  questions = await response.json()
131
 
 
132
  question_map = {q["id"]: q["title"] for q in questions}
 
 
133
  grouped_answers = defaultdict(list)
134
 
135
  for answer in user_answers:
 
139
  "answer": answer.get("answers", [])
140
  })
141
 
 
142
  for user in users:
143
  user["answers"] = grouped_answers.get(user["id"], [])
144
 
 
148
  logger.error(f"❌ Erro ao buscar usuários e respostas: {str(e)}")
149
  raise HTTPException(status_code=500, detail="Erro interno do servidor")
150
 
151
+ # ✅ Aprovar conta
152
  @router.post("/admin/approve-account")
153
  async def approve_account(
154
  body: ApproveAccountRequest,
155
  user_token: str = Header(None, alias="User-key")
156
  ):
 
 
 
157
  try:
158
  await verify_admin_token(user_token)
159
 
160
  update_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{body.user_id}"
161
+ payload = { "approved_account": True }
 
 
162
 
163
  async with aiohttp.ClientSession() as session:
164
+ async with session.patch(update_url, headers=SUPABASE_ROLE_HEADERS, json=payload) as response:
165
  if response.status != 204:
166
  logger.error(f"❌ Erro ao aprovar conta: {response.status}")
167
  raise HTTPException(status_code=500, detail="Erro ao aprovar a conta")
 
174
  logger.error(f"❌ Erro ao aprovar conta: {str(e)}")
175
  raise HTTPException(status_code=500, detail=str(e))
176
 
177
+ # ❌ Reprovar conta
178
  @router.post("/admin/reject-account")
179
  async def reject_account(
180
  body: RejectAccountRequest,
181
  user_token: str = Header(None, alias="User-key")
182
  ):
 
 
 
183
  try:
184
  await verify_admin_token(user_token)
185
 
 
190
  }
191
 
192
  async with aiohttp.ClientSession() as session:
193
+ async with session.patch(update_url, headers=SUPABASE_ROLE_HEADERS, json=payload) as response:
194
  if response.status != 204:
195
  logger.error(f"❌ Erro ao reprovar conta: {response.status}")
196
  raise HTTPException(status_code=500, detail="Erro ao reprovar a conta")
 
203
  logger.error(f"❌ Erro ao reprovar conta: {str(e)}")
204
  raise HTTPException(status_code=500, detail=str(e))
205
 
206
+ # 🔍 Listar contas pendentes
207
  @router.get("/admin/pending-approvals")
208
  async def pending_approvals_endpoint(
209
  user_token: str = Header(None, alias="User-key")
210
  ):
 
 
 
 
211
  try:
212
  await verify_admin_token(user_token)
213
  return await get_users_pending_approval()
 
215
  raise he
216
  except Exception as e:
217
  logger.error(f"❌ Erro no endpoint de aprovações: {str(e)}")
218
+ raise HTTPException(status_code=500, detail=str(e))