chat.py 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, Query, HTTPException
  2. from services.chat_manager import manager
  3. import db
  4. import auth_utils
  5. import datetime
  6. import schemas
  7. router = APIRouter(tags=["chat"])
  8. @router.get("/orders/{order_id}/messages")
  9. async def get_order_messages(order_id: int, token: str = Depends(auth_utils.oauth2_scheme)):
  10. payload = auth_utils.decode_token(token)
  11. if not payload: raise HTTPException(status_code=401, detail="Invalid token")
  12. role = payload.get("role")
  13. user_id = payload.get("id")
  14. order = db.execute_query("SELECT user_id FROM orders WHERE id = %s", (order_id,))
  15. if not order: raise HTTPException(status_code=404, detail="Order not found")
  16. if role != 'admin' and order[0]['user_id'] != user_id: raise HTTPException(status_code=403, detail="Not authorized")
  17. messages = db.execute_query("SELECT id, is_from_admin, message, created_at FROM order_messages WHERE order_id = %s ORDER BY created_at ASC", (order_id,))
  18. for msg in messages:
  19. if msg.get('created_at'): msg['created_at'] = msg['created_at'].isoformat()
  20. # Mark messages as read
  21. if role == 'admin':
  22. db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = FALSE AND is_read = FALSE", (order_id,))
  23. else:
  24. db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = TRUE AND is_read = FALSE", (order_id,))
  25. return messages
  26. @router.post("/orders/{order_id}/messages")
  27. async def post_order_message(order_id: int, data: schemas.MessageCreate, token: str = Depends(auth_utils.oauth2_scheme)):
  28. payload = auth_utils.decode_token(token)
  29. if not payload: raise HTTPException(status_code=401, detail="Invalid token")
  30. message = data.message.strip()
  31. if not message: raise HTTPException(status_code=400, detail="Empty message")
  32. role = payload.get("role")
  33. user_id = payload.get("id")
  34. is_admin = (role == 'admin')
  35. order = db.execute_query("SELECT user_id FROM orders WHERE id = %s", (order_id,))
  36. if not order: raise HTTPException(status_code=404, detail="Order not found")
  37. if not is_admin and order[0]['user_id'] != user_id: raise HTTPException(status_code=403, detail="Not authorized")
  38. query = "INSERT INTO order_messages (order_id, user_id, is_from_admin, message) VALUES (%s, %s, %s, %s)"
  39. msg_id = db.execute_commit(query, (order_id, user_id, is_admin, message))
  40. now = datetime.datetime.utcnow().isoformat()
  41. await manager.broadcast_to_order(order_id, {"id": msg_id, "is_from_admin": is_admin, "message": message, "created_at": now})
  42. return {"id": msg_id, "status": "sent"}
  43. @router.websocket("/ws/chat/{order_id}")
  44. async def ws_chat(websocket: WebSocket, order_id: int, token: str = Query(...)):
  45. payload = auth_utils.decode_token(token)
  46. if not payload:
  47. await websocket.close(code=4001)
  48. return
  49. role = payload.get("role")
  50. user_id = payload.get("id")
  51. order = db.execute_query("SELECT user_id FROM orders WHERE id = %s", (order_id,))
  52. if not order:
  53. await websocket.close(code=4004)
  54. return
  55. if role != 'admin' and order[0]['user_id'] != user_id:
  56. await websocket.close(code=4003)
  57. return
  58. await manager.connect(websocket, order_id, role)
  59. try:
  60. while True:
  61. data = await websocket.receive_text()
  62. if data == "typing":
  63. await manager.broadcast_to_order(order_id, {"type": "typing", "is_admin": role == 'admin'})
  64. elif data == "stop_typing":
  65. await manager.broadcast_to_order(order_id, {"type": "stop_typing", "is_admin": role == 'admin'})
  66. except WebSocketDisconnect:
  67. manager.disconnect(websocket, order_id)