fix: Move /approve route before /{claim_id} to fix 405 error
Fixed route conflict:
- Moved POST /approve route BEFORE GET /{claim_id}
- FastAPI processes routes in order, so specific routes must come before parameterized ones
- This fixes 405 Method Not Allowed error
Files:
- backend/app/api/claims.py
This commit is contained in:
@@ -451,6 +451,83 @@ async def delete_draft(claim_id: str):
|
|||||||
raise HTTPException(status_code=500, detail=f"Ошибка при удалении черновика: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Ошибка при удалении черновика: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/approve")
|
||||||
|
async def publish_form_approval(request: Request):
|
||||||
|
"""
|
||||||
|
Публикация данных подтвержденной формы в Redis канал
|
||||||
|
|
||||||
|
После SMS-апрува отправляет данные формы в Redis канал clientright:webform:approve
|
||||||
|
для обработки в n8n workflow.
|
||||||
|
|
||||||
|
В будущем можно подключить RabbitMQ для очереди и защиты от дублей.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
body = await request.json()
|
||||||
|
|
||||||
|
claim_id = body.get("claim_id")
|
||||||
|
session_token = body.get("session_token") or body.get("session_id")
|
||||||
|
|
||||||
|
if not claim_id:
|
||||||
|
raise HTTPException(status_code=400, detail="claim_id обязателен")
|
||||||
|
|
||||||
|
# Генерируем idempotency key для защиты от дублей (для будущей интеграции с RabbitMQ)
|
||||||
|
import time
|
||||||
|
idempotency_key = f"{claim_id}_{int(time.time() * 1000)}_{body.get('user_id', 'unknown')}"
|
||||||
|
|
||||||
|
# Формируем событие для Redis
|
||||||
|
event_data = {
|
||||||
|
"event_type": "form_approve",
|
||||||
|
"status": "approved",
|
||||||
|
"message": "Форма подтверждена после SMS-верификации",
|
||||||
|
"claim_id": claim_id,
|
||||||
|
"session_token": session_token,
|
||||||
|
"unified_id": body.get("unified_id"),
|
||||||
|
"phone": body.get("phone"),
|
||||||
|
"sms_verified": True,
|
||||||
|
"idempotency_key": idempotency_key, # Для защиты от дублей в RabbitMQ
|
||||||
|
"timestamp": datetime.utcnow().isoformat(),
|
||||||
|
|
||||||
|
# Данные формы подтверждения
|
||||||
|
"form_data": body.get("form_data", {}),
|
||||||
|
"user": body.get("user", {}),
|
||||||
|
"project": body.get("project", {}),
|
||||||
|
"offenders": body.get("offenders", []),
|
||||||
|
"meta": body.get("meta", {}),
|
||||||
|
|
||||||
|
# Оригинальные данные для сравнения
|
||||||
|
"original_data": body.get("original_data", {}),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Публикуем в Redis канал clientright:webform:approve
|
||||||
|
channel = "clientright:webform:approve"
|
||||||
|
event_json = json.dumps(event_data, ensure_ascii=False)
|
||||||
|
await redis_service.publish(channel, event_json)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"📢 Form approval published to {channel}",
|
||||||
|
extra={
|
||||||
|
"claim_id": claim_id,
|
||||||
|
"idempotency_key": idempotency_key,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"channel": channel,
|
||||||
|
"idempotency_key": idempotency_key,
|
||||||
|
"message": "Данные формы отправлены на обработку",
|
||||||
|
}
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("❌ Failed to publish form approval")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=f"Ошибка при отправке данных формы: {str(e)}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{claim_id}")
|
@router.get("/{claim_id}")
|
||||||
async def get_claim(claim_id: str):
|
async def get_claim(claim_id: str):
|
||||||
"""Получить информацию о заявке по ID"""
|
"""Получить информацию о заявке по ID"""
|
||||||
@@ -541,83 +618,6 @@ async def load_wizard_data(claim_id: str):
|
|||||||
raise HTTPException(status_code=500, detail=f"Ошибка при загрузке данных визарда: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Ошибка при загрузке данных визарда: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/approve")
|
|
||||||
async def publish_form_approval(request: Request):
|
|
||||||
"""
|
|
||||||
Публикация данных подтвержденной формы в Redis канал
|
|
||||||
|
|
||||||
После SMS-апрува отправляет данные формы в Redis канал clientright:webform:approve
|
|
||||||
для обработки в n8n workflow.
|
|
||||||
|
|
||||||
В будущем можно подключить RabbitMQ для очереди и защиты от дублей.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
body = await request.json()
|
|
||||||
|
|
||||||
claim_id = body.get("claim_id")
|
|
||||||
session_token = body.get("session_token") or body.get("session_id")
|
|
||||||
|
|
||||||
if not claim_id:
|
|
||||||
raise HTTPException(status_code=400, detail="claim_id обязателен")
|
|
||||||
|
|
||||||
# Генерируем idempotency key для защиты от дублей (для будущей интеграции с RabbitMQ)
|
|
||||||
import time
|
|
||||||
idempotency_key = f"{claim_id}_{int(time.time() * 1000)}_{body.get('user_id', 'unknown')}"
|
|
||||||
|
|
||||||
# Формируем событие для Redis
|
|
||||||
event_data = {
|
|
||||||
"event_type": "form_approve",
|
|
||||||
"status": "approved",
|
|
||||||
"message": "Форма подтверждена после SMS-верификации",
|
|
||||||
"claim_id": claim_id,
|
|
||||||
"session_token": session_token,
|
|
||||||
"unified_id": body.get("unified_id"),
|
|
||||||
"phone": body.get("phone"),
|
|
||||||
"sms_verified": True,
|
|
||||||
"idempotency_key": idempotency_key, # Для защиты от дублей в RabbitMQ
|
|
||||||
"timestamp": datetime.utcnow().isoformat(),
|
|
||||||
|
|
||||||
# Данные формы подтверждения
|
|
||||||
"form_data": body.get("form_data", {}),
|
|
||||||
"user": body.get("user", {}),
|
|
||||||
"project": body.get("project", {}),
|
|
||||||
"offenders": body.get("offenders", []),
|
|
||||||
"meta": body.get("meta", {}),
|
|
||||||
|
|
||||||
# Оригинальные данные для сравнения
|
|
||||||
"original_data": body.get("original_data", {}),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Публикуем в Redis канал clientright:webform:approve
|
|
||||||
channel = "clientright:webform:approve"
|
|
||||||
event_json = json.dumps(event_data, ensure_ascii=False)
|
|
||||||
await redis_service.publish(channel, event_json)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"📢 Form approval published to {channel}",
|
|
||||||
extra={
|
|
||||||
"claim_id": claim_id,
|
|
||||||
"idempotency_key": idempotency_key,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"channel": channel,
|
|
||||||
"idempotency_key": idempotency_key,
|
|
||||||
"message": "Данные формы отправлены на обработку",
|
|
||||||
}
|
|
||||||
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception("❌ Failed to publish form approval")
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=500,
|
|
||||||
detail=f"Ошибка при отправке данных формы: {str(e)}",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/description")
|
@router.post("/description")
|
||||||
async def publish_ticket_form_description(payload: TicketFormDescriptionRequest):
|
async def publish_ticket_form_description(payload: TicketFormDescriptionRequest):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user