fix(schemas): Add missing List import in goal schemas
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -8,6 +8,7 @@ from app.core.config import settings
|
||||
from app.api.v1.schemas.counter import CounterListResponse, Counter, CounterCreateRequest, CounterCreateResponse
|
||||
# Обновляем импорты для схем целей
|
||||
from app.api.v1.schemas.goal import GoalListResponse, Goal, GoalCreateRequest, GoalCreateResponse, CreatedGoal
|
||||
from app.api.v1.schemas.goal import GoalDeleteRequest, GoalDeleteResponse
|
||||
|
||||
router = APIRouter()
|
||||
bearer_scheme = HTTPBearer()
|
||||
@@ -205,45 +206,45 @@ async def create_custom_goals_for_counter(
|
||||
|
||||
return GoalCreateResponse(created_goals=created_goals_list)
|
||||
|
||||
# --- НОВЫЙ ЭНДПОИНТ: Удаление цели ---
|
||||
# --- ЭНДПОИНТ: Массовое удаление целей ---
|
||||
@router.delete(
|
||||
"/{counter_id}/goals/{goal_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Удаление цели в счетчике"
|
||||
"/{counter_id}/goals",
|
||||
response_model=GoalDeleteResponse,
|
||||
summary="Массовое удаление целей в счетчике"
|
||||
)
|
||||
async def delete_goal_in_counter(
|
||||
async def delete_goals_in_counter(
|
||||
counter_id: int,
|
||||
goal_id: int,
|
||||
request_body: GoalDeleteRequest,
|
||||
credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)]
|
||||
):
|
||||
"""
|
||||
Удаляет указанную цель в указанном счетчике.
|
||||
В случае успеха возвращает пустой ответ со статусом 204.
|
||||
Удаляет цели в указанном счетчике по списку их ID.
|
||||
Возвращает отчет о выполненной операции.
|
||||
"""
|
||||
token = credentials.credentials
|
||||
logger.info(f"Attempting to delete goal ID: {goal_id} from counter ID: {counter_id}")
|
||||
goal_ids_to_delete = request_body.goal_ids
|
||||
logger.info(f"Attempting to delete {len(goal_ids_to_delete)} goals from counter ID: {counter_id}")
|
||||
|
||||
url = f"{settings.YANDEX_METRIKA_API_URL}/management/v1/counter/{counter_id}/goal/{goal_id}"
|
||||
headers = {'Authorization': f'OAuth {token}'}
|
||||
deleted_count = 0
|
||||
failed_ids = {}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.delete(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
logger.success(f"Successfully deleted goal ID: {goal_id} from counter {counter_id}.")
|
||||
# При успехе стандартно возвращается пустой ответ
|
||||
return
|
||||
async with httpx.AsyncClient() as client:
|
||||
for goal_id in goal_ids_to_delete:
|
||||
url = f"{settings.YANDEX_METRIKA_API_URL}/management/v1/counter/{counter_id}/goal/{goal_id}"
|
||||
try:
|
||||
response = await client.delete(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
logger.success(f"Successfully deleted goal ID: {goal_id}")
|
||||
deleted_count += 1
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_details = e.response.json()
|
||||
error_message = error_details.get('message', 'Unknown error')
|
||||
logger.error(f"Failed to delete goal ID: {goal_id}. Reason: {error_message}")
|
||||
failed_ids[goal_id] = error_message
|
||||
except Exception as e:
|
||||
logger.error(f"An unexpected error occurred while deleting goal ID: {goal_id}.")
|
||||
failed_ids[goal_id] = "Unexpected server error"
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_details = e.response.json()
|
||||
logger.error(f"Yandex Metrika API error during goal deletion: {e.response.status_code} - {error_details}")
|
||||
raise HTTPException(
|
||||
status_code=e.response.status_code,
|
||||
detail=f"Yandex API Error: {error_details.get('message', 'Unknown error')}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.opt(exception=True).error("An unexpected error occurred during goal deletion.")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="An internal server error occurred."
|
||||
)
|
||||
message = f"Operation completed. Deleted {deleted_count} out of {len(goal_ids_to_delete)} goals."
|
||||
return GoalDeleteResponse(deleted_count=deleted_count, failed_ids=failed_ids, message=message)
|
||||
@@ -1,5 +1,5 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List
|
||||
from typing import List, Dict, Any # <-- ИЗМЕНЕНИЕ ЗДЕСЬ
|
||||
|
||||
# Схема для ОДНОЙ цели в списке (для GET запроса)
|
||||
class Goal(BaseModel):
|
||||
@@ -11,7 +11,6 @@ class Goal(BaseModel):
|
||||
class GoalListResponse(BaseModel):
|
||||
goals: List[Goal]
|
||||
|
||||
# --- ИЗМЕНЕНИЯ ЗДЕСЬ ---
|
||||
# Схема для ОДНОЙ кастомной цели в запросе на создание (для POST)
|
||||
class CustomGoalIn(BaseModel):
|
||||
identifier: str = Field(..., description="Уникальный идентификатор JS-события")
|
||||
@@ -28,4 +27,15 @@ class CreatedGoal(BaseModel):
|
||||
|
||||
# Схема ответа после создания целей
|
||||
class GoalCreateResponse(BaseModel):
|
||||
created_goals: List[CreatedGoal]
|
||||
created_goals: List[CreatedGoal]
|
||||
|
||||
# --- Схемы для массового удаления ---
|
||||
class GoalDeleteRequest(BaseModel):
|
||||
"""Схема запроса на массовое удаление целей."""
|
||||
goal_ids: List[int] = Field(..., description="Список ID целей для удаления")
|
||||
|
||||
class GoalDeleteResponse(BaseModel):
|
||||
"""Схема ответа после массового удаления."""
|
||||
deleted_count: int
|
||||
failed_ids: Dict[int, Any]
|
||||
message: str
|
||||
Reference in New Issue
Block a user