habulaj commited on
Commit
c2bb33b
·
verified ·
1 Parent(s): c6f1c6d

Update routes/onboarding.py

Browse files
Files changed (1) hide show
  1. routes/onboarding.py +32 -87
routes/onboarding.py CHANGED
@@ -1,12 +1,9 @@
1
  import os
2
  import logging
3
  import aiohttp
4
- import asyncio
5
  from pydantic import BaseModel
6
  from fastapi import APIRouter, HTTPException, Body, Query, Header
7
  from typing import List, Dict, Any, Optional, Union
8
- from functools import lru_cache
9
- import requests
10
 
11
  router = APIRouter()
12
 
@@ -48,64 +45,9 @@ SUPABASE_ROLE_HEADERS = {
48
  logging.basicConfig(level=logging.INFO)
49
  logger = logging.getLogger(__name__)
50
 
51
- # Cache para reduzir chamadas repetidas
52
- @lru_cache(maxsize=128)
53
- def get_cached_admin_status(user_id: str) -> bool:
54
- """Obtém e armazena em cache se um usuário é admin"""
55
- user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
56
- response = requests.get(user_data_url, headers=SUPABASE_HEADERS)
57
-
58
- if response.status_code != 200 or not response.json():
59
- return False
60
-
61
- user_info = response.json()[0]
62
- return user_info.get("is_admin", False)
63
-
64
- # Função para obter permissões do usuário
65
- async def get_user_permissions(user_id: str) -> Dict[str, bool]:
66
- """Obtém as permissões de um usuário"""
67
- user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}&select=is_admin,edit_onboarding"
68
-
69
- async with aiohttp.ClientSession() as session:
70
- async with session.get(user_data_url, headers=SUPABASE_HEADERS) as response:
71
- if response.status != 200 or not await response.json():
72
- return {"is_admin": False, "edit_onboarding": False}
73
-
74
- user_info = (await response.json())[0]
75
- return {
76
- "is_admin": user_info.get("is_admin", False),
77
- "edit_onboarding": user_info.get("edit_onboarding", False)
78
- }
79
-
80
- # Verificação de token admin (mantida para compatibilidade)
81
- async def verify_admin_token(user_token: str) -> str:
82
- """Verifica se o token pertence a um administrador de forma assíncrona"""
83
- headers = {
84
- "Authorization": f"Bearer {user_token}",
85
- "apikey": SUPABASE_KEY,
86
- "Content-Type": "application/json"
87
- }
88
-
89
- async with aiohttp.ClientSession() as session:
90
- async with session.get(f"{SUPABASE_URL}/auth/v1/user", headers=headers) as response:
91
- if response.status != 200:
92
- raise HTTPException(status_code=401, detail="Token inválido ou expirado")
93
-
94
- user_data = await response.json()
95
- user_id = user_data.get("id")
96
- if not user_id:
97
- raise HTTPException(status_code=400, detail="ID do usuário não encontrado")
98
-
99
- is_admin = await asyncio.to_thread(get_cached_admin_status, user_id)
100
-
101
- if not is_admin:
102
- raise HTTPException(status_code=403, detail="Acesso negado: privilégios de administrador necessários")
103
-
104
- return user_id
105
-
106
- # Verificação de token com permissões específicas
107
  async def verify_token_with_permissions(user_token: str, required_permission: Optional[str] = None) -> Dict[str, Any]:
108
- """Verifica o token e verifica se o usuário tem a permissão necessária"""
109
  headers = {
110
  "Authorization": f"Bearer {user_token}",
111
  "apikey": SUPABASE_KEY,
@@ -123,26 +65,32 @@ async def verify_token_with_permissions(user_token: str, required_permission: Op
123
  raise HTTPException(status_code=400, detail="ID do usuário não encontrado")
124
 
125
  # Obter permissões do usuário
126
- permissions = await get_user_permissions(user_id)
127
-
128
- # Verificar se é admin
129
- is_admin = permissions.get("is_admin", False)
130
- if not is_admin:
131
- raise HTTPException(status_code=403, detail="Acesso negado: privilégios de administrador necessários")
132
 
133
- # Verificar permissão específica, se requisitada
134
- if required_permission:
135
- has_permission = permissions.get(required_permission, False)
136
- if not has_permission:
137
- raise HTTPException(
138
- status_code=403,
139
- detail=f"Acesso negado: permissão '{required_permission}' necessária"
140
- )
 
 
 
 
 
 
 
 
 
 
 
141
 
142
  return {
143
  "user_id": user_id,
144
  "is_admin": is_admin,
145
- "permissions": permissions
146
  }
147
 
148
  @router.patch("/onboarding/update-question")
@@ -153,11 +101,12 @@ async def update_onboarding_question(
153
  """
154
  Atualiza uma pergunta de onboarding com base no ID.
155
  Apenas os campos enviados no payload serão atualizados.
 
156
  """
157
  try:
158
  # Verificar se o usuário é admin e tem permissão para editar onboarding
159
  await verify_token_with_permissions(user_token, "edit_onboarding")
160
-
161
  update_data = {}
162
 
163
  if payload.title is not None:
@@ -200,11 +149,12 @@ async def add_onboarding_question(
200
  """
201
  Adiciona uma nova pergunta de onboarding.
202
  Trata casos onde `options` vem como `{}` ou string.
 
203
  """
204
  try:
205
  # Verificar se o usuário é admin e tem permissão para editar onboarding
206
  await verify_token_with_permissions(user_token, "edit_onboarding")
207
-
208
  # Tratamento de `options`
209
  options = payload.options
210
 
@@ -249,11 +199,12 @@ async def delete_onboarding_question(
249
  ):
250
  """
251
  Deleta uma pergunta de onboarding com base no ID (passado via query parameter).
 
252
  """
253
  try:
254
  # Verificar se o usuário é admin e tem permissão para editar onboarding
255
  await verify_token_with_permissions(user_token, "edit_onboarding")
256
-
257
  query_url = f"{SUPABASE_URL}/rest/v1/Onboarding?id=eq.{id}"
258
  headers = SUPABASE_ROLE_HEADERS.copy()
259
  headers["Prefer"] = "return=representation"
@@ -278,20 +229,15 @@ async def delete_onboarding_question(
278
  raise HTTPException(status_code=500, detail="Erro interno do servidor")
279
 
280
  @router.get("/onboarding/questions")
281
- async def get_onboarding_questions(
282
- user_token: str = Header(None, alias="User-key")
283
- ) -> Dict[str, List[Dict[str, Any]]]:
284
  """
285
  Retorna todas as perguntas de onboarding, separadas por target_type (client e stylist).
 
286
  """
287
  try:
288
  # Verificar se o usuário é admin e tem permissão para editar onboarding
289
- # Adicionamos um log para verificar o que está acontecendo
290
- logger.info(f"Recebido token: {user_token[:10]}... para acesso às perguntas de onboarding")
291
-
292
  await verify_token_with_permissions(user_token, "edit_onboarding")
293
- logger.info("Token verificado com sucesso!")
294
-
295
  query_url = f"{SUPABASE_URL}/rest/v1/Onboarding?select=id,title,description,question_type,options,target_type,optional,lock&order=created_at.asc"
296
  headers = SUPABASE_HEADERS.copy()
297
  headers["Accept"] = "application/json"
@@ -330,7 +276,6 @@ async def get_onboarding_questions(
330
  }
331
 
332
  except HTTPException as he:
333
- logger.error(f"❌ HTTPException: {he.detail}")
334
  raise he
335
  except Exception as e:
336
  logger.error(f"❌ Erro ao obter perguntas de onboarding: {str(e)}")
 
1
  import os
2
  import logging
3
  import aiohttp
 
4
  from pydantic import BaseModel
5
  from fastapi import APIRouter, HTTPException, Body, Query, Header
6
  from typing import List, Dict, Any, Optional, Union
 
 
7
 
8
  router = APIRouter()
9
 
 
45
  logging.basicConfig(level=logging.INFO)
46
  logger = logging.getLogger(__name__)
47
 
48
+ # Função para verificar token e permissões
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  async def verify_token_with_permissions(user_token: str, required_permission: Optional[str] = None) -> Dict[str, Any]:
50
+ """Verifica o token e retorna ID do usuário e suas permissões"""
51
  headers = {
52
  "Authorization": f"Bearer {user_token}",
53
  "apikey": SUPABASE_KEY,
 
65
  raise HTTPException(status_code=400, detail="ID do usuário não encontrado")
66
 
67
  # Obter permissões do usuário
68
+ user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}&select=is_admin,edit_onboarding"
 
 
 
 
 
69
 
70
+ async with aiohttp.ClientSession() as session:
71
+ async with session.get(user_data_url, headers=SUPABASE_HEADERS) as response:
72
+ if response.status != 200 or not await response.json():
73
+ raise HTTPException(status_code=403, detail="Acesso negado: não foi possível verificar permissões")
74
+
75
+ user_info = (await response.json())[0]
76
+ is_admin = user_info.get("is_admin", False)
77
+
78
+ if not is_admin:
79
+ raise HTTPException(status_code=403, detail="Acesso negado: privilégios de administrador necessários")
80
+
81
+ # Verificar permissão específica, se requisitada
82
+ if required_permission:
83
+ has_permission = user_info.get(required_permission, False)
84
+ if not has_permission:
85
+ raise HTTPException(
86
+ status_code=403,
87
+ detail=f"Acesso negado: permissão '{required_permission}' necessária"
88
+ )
89
 
90
  return {
91
  "user_id": user_id,
92
  "is_admin": is_admin,
93
+ "permissions": user_info
94
  }
95
 
96
  @router.patch("/onboarding/update-question")
 
101
  """
102
  Atualiza uma pergunta de onboarding com base no ID.
103
  Apenas os campos enviados no payload serão atualizados.
104
+ Requer permissão de admin e edit_onboarding=true.
105
  """
106
  try:
107
  # Verificar se o usuário é admin e tem permissão para editar onboarding
108
  await verify_token_with_permissions(user_token, "edit_onboarding")
109
+
110
  update_data = {}
111
 
112
  if payload.title is not None:
 
149
  """
150
  Adiciona uma nova pergunta de onboarding.
151
  Trata casos onde `options` vem como `{}` ou string.
152
+ Requer permissão de admin e edit_onboarding=true.
153
  """
154
  try:
155
  # Verificar se o usuário é admin e tem permissão para editar onboarding
156
  await verify_token_with_permissions(user_token, "edit_onboarding")
157
+
158
  # Tratamento de `options`
159
  options = payload.options
160
 
 
199
  ):
200
  """
201
  Deleta uma pergunta de onboarding com base no ID (passado via query parameter).
202
+ Requer permissão de admin e edit_onboarding=true.
203
  """
204
  try:
205
  # Verificar se o usuário é admin e tem permissão para editar onboarding
206
  await verify_token_with_permissions(user_token, "edit_onboarding")
207
+
208
  query_url = f"{SUPABASE_URL}/rest/v1/Onboarding?id=eq.{id}"
209
  headers = SUPABASE_ROLE_HEADERS.copy()
210
  headers["Prefer"] = "return=representation"
 
229
  raise HTTPException(status_code=500, detail="Erro interno do servidor")
230
 
231
  @router.get("/onboarding/questions")
232
+ async def get_onboarding_questions(user_token: str = Header(None, alias="User-key")) -> Dict[str, List[Dict[str, Any]]]:
 
 
233
  """
234
  Retorna todas as perguntas de onboarding, separadas por target_type (client e stylist).
235
+ Requer permissão de admin e edit_onboarding=true.
236
  """
237
  try:
238
  # Verificar se o usuário é admin e tem permissão para editar onboarding
 
 
 
239
  await verify_token_with_permissions(user_token, "edit_onboarding")
240
+
 
241
  query_url = f"{SUPABASE_URL}/rest/v1/Onboarding?select=id,title,description,question_type,options,target_type,optional,lock&order=created_at.asc"
242
  headers = SUPABASE_HEADERS.copy()
243
  headers["Accept"] = "application/json"
 
276
  }
277
 
278
  except HTTPException as he:
 
279
  raise he
280
  except Exception as e:
281
  logger.error(f"❌ Erro ao obter perguntas de onboarding: {str(e)}")