Skip to content

Commit c87227c

Browse files
committed
broadcast_chat_created 수정
1 parent 8577345 commit c87227c

File tree

3 files changed

+84
-24
lines changed

3 files changed

+84
-24
lines changed

app/routers/chat_list_ws.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,14 @@ def _build_chat_created_payload(chat: ChatRoom, me_id: int, db: Session) -> Opti
130130
# ---------- 외부에서 호출하는 브로드캐스트 함수들 ----------
131131

132132
async def broadcast_chat_created(chat: ChatRoom, db: Session):
133-
"""새 채팅방 생성 시 buyer/seller 둘 다에게 chat_created 이벤트"""
134-
users = [chat.buyer_id, chat.seller_id]
135-
for uid in users:
136-
payload = _build_chat_created_payload(chat, uid, db)
137-
if payload:
138-
await broadcast_to_user(uid, "chat_created", payload)
133+
"""새 채팅방 생성 시 판매자(seller)에게만 chat_created 이벤트"""
134+
135+
seller_id = chat.seller_id
136+
137+
payload = _build_chat_created_payload(chat, seller_id, db)
138+
if payload:
139+
await broadcast_to_user(seller_id, "chat_created", payload)
140+
139141

140142

141143
async def broadcast_chat_list_update(chat: ChatRoom, last_msg: ChatMessage, db: Session):

app/routers/chat_rest.py

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
# app/routers/chat_rest.py
2-
from fastapi import APIRouter, Depends, HTTPException, Query, Path
2+
from fastapi import APIRouter, Depends, HTTPException, Query, Path, BackgroundTasks # 🔹 BackgroundTasks 추가
33
from pydantic import BaseModel
44
from typing import Optional, List
55
from sqlalchemy.orm import Session
66
from datetime import datetime, timezone
7-
import asyncio
87

98
from app.core.db import get_db
109
from app.core.auth import get_current_user
1110
from app.models.user import User
1211
from app.models.posting import Posting
1312
from app.models.chat import ChatRoom, ChatMessage, ChatRead
1413
from app.routers import chat_ws
14+
from app.routers.chat_list_ws import broadcast_chat_created # 🔹 추가
1515

1616
router = APIRouter(prefix="/api/chat", tags=["Chat REST"])
1717

18+
# 🔹 채팅방 생성 요청/응답 모델 추가
19+
class CreateChatIn(BaseModel):
20+
postingId: int
21+
22+
class CreateChatOut(BaseModel):
23+
chatId: int
24+
postingId: int
25+
sellerId: int
26+
buyerId: int
27+
createdAt: str
28+
1829

1930
class MessageItem(BaseModel):
2031
messageId: int
@@ -46,6 +57,46 @@ class DealStatusOut(BaseModel):
4657
changedAt: str
4758

4859

60+
# 🔥 새 채팅방 생성 + 판매자에게만 chat_created 브로드캐스트
61+
@router.post("", response_model=CreateChatOut)
62+
def create_chat(
63+
body: CreateChatIn,
64+
background_tasks: BackgroundTasks,
65+
db: Session = Depends(get_db),
66+
me: User = Depends(get_current_user),
67+
):
68+
# 1) 게시글 확인
69+
posting = db.query(Posting).filter(Posting.id == body.postingId).first()
70+
if not posting:
71+
raise HTTPException(status_code=404, detail="posting_not_found")
72+
73+
# 2) 자기 자신에게 채팅 방지
74+
if posting.seller_id == me.user_id:
75+
raise HTTPException(status_code=400, detail="cannot_chat_with_self")
76+
77+
# 3) 채팅방 생성 (buyer = me, seller = 게시글 작성자)
78+
room = ChatRoom(
79+
posting_id=posting.id,
80+
seller_id=posting.seller_id,
81+
buyer_id=me.user_id,
82+
# status는 모델 default 있으면 생략 가능
83+
)
84+
db.add(room)
85+
db.commit()
86+
db.refresh(room)
87+
88+
# 4) 🔔 판매자에게만 chat_created 이벤트 전송 (백그라운드)
89+
background_tasks.add_task(broadcast_chat_created, room, db)
90+
91+
return CreateChatOut(
92+
chatId=room.id,
93+
postingId=room.posting_id,
94+
sellerId=room.seller_id,
95+
buyerId=room.buyer_id,
96+
createdAt=room.created_at.astimezone(timezone.utc).isoformat(),
97+
)
98+
99+
49100
@router.get("/{chat_id}", response_model=MessagesOut)
50101
def list_messages(
51102
chat_id: int = Path(...),
@@ -70,9 +121,9 @@ def list_messages(
70121

71122
messages: List[MessageItem] = []
72123
for m in rows:
73-
if m.type == "SYSTEM":
124+
if m.type.upper() == "SYSTEM":
74125
is_mine = False
75-
read = True # 시스템 메세지는 그냥 항상 읽은 걸로 취급
126+
read = True # 시스템 메세지는 항상 읽은 걸로 취급
76127
else:
77128
is_mine = (m.sender_id == me.user_id)
78129
read = db.query(ChatRead).filter(ChatRead.message_id == m.id).count() > 0
@@ -91,23 +142,22 @@ def list_messages(
91142
next_cursor = rows[-1].id if rows else None
92143
return MessagesOut(messages=messages, hasNext=has_next, nextCursor=next_cursor)
93144

145+
94146
@router.patch("/{chat_id}/deal", response_model=DealStatusOut)
95147
async def update_deal_status(
96148
chat_id: int = Path(..., description="대상 채팅방 ID"),
97149
body: UpdateDealStatusIn = ...,
98150
db: Session = Depends(get_db),
99151
me: User = Depends(get_current_user),
100152
):
101-
# 1) 채팅방 조회
153+
# 이하 내용은 네가 올린 그대로 (거래 상태 변경 + system 메시지 + broadcast_deal_update)
102154
room = db.query(ChatRoom).filter(ChatRoom.id == chat_id).first()
103155
if not room:
104156
raise HTTPException(status_code=404, detail="chat_not_found")
105157

106-
# 2) 권한 체크
107158
if me.user_id not in (room.buyer_id, room.seller_id):
108159
raise HTTPException(status_code=403, detail="forbidden")
109160

110-
# 3) 허용 status만
111161
allowed = {"ACTIVE", "RESERVED", "COMPLETED"}
112162
if body.status not in allowed:
113163
raise HTTPException(status_code=400, detail="invalid_status")
@@ -121,33 +171,27 @@ async def update_deal_status(
121171
if prev_status == new_status:
122172
raise HTTPException(status_code=400, detail="same_status")
123173

124-
# 4) 게시글 조회
125174
posting = db.query(Posting).filter(Posting.id == room.posting_id).first()
126175
if not posting:
127176
raise HTTPException(status_code=404, detail="posting_not_found")
128177

129-
# 5) posting.status 연동
130178
if prev_status == "ACTIVE" and new_status == "RESERVED":
131179
if posting.status == "SELLING":
132180
posting.status = "RESERVED"
133-
134181
elif prev_status == "RESERVED" and new_status == "ACTIVE":
135182
if posting.status == "RESERVED":
136183
posting.status = "SELLING"
137-
138184
elif prev_status == "RESERVED" and new_status == "COMPLETED":
139185
if posting.status == "RESERVED":
140186
posting.status = "SOLD"
141187

142188
seller = db.query(User).filter(User.user_id == room.seller_id).first()
143189
buyer = db.query(User).filter(User.user_id == room.buyer_id).first()
144-
145190
if seller is not None:
146191
seller.sell_count = (seller.sell_count or 0) + 1
147192
if buyer is not None:
148193
buyer.buy_count = (buyer.buy_count or 0) + 1
149194

150-
# 6) 채팅방 상태 변경
151195
room.status = new_status
152196
changed_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
153197

@@ -166,24 +210,21 @@ async def update_deal_status(
166210
else:
167211
msg_text = f"{nick}님이 거래 상태를 변경했습니다"
168212

169-
# ✅ 시스템 메시지를 ChatMessage 로 저장
170213
system_msg = ChatMessage(
171214
room_id=room.id,
172-
sender_id=me.user_id, # 시스템이라서 보낸 사람 없음
215+
sender_id=me.user_id,
173216
type="system",
174217
content=msg_text,
175218
)
176219
db.add(system_msg)
177220
db.commit()
178221
db.refresh(system_msg)
179222

180-
# ✅ 기존처럼 브로드캐스트 (필요하면 messageId도 같이 넘겨도 됨)
181223
await chat_ws.broadcast_deal_update(
182224
chat_id=room.id,
183225
deal_status=new_status,
184226
post_status=posting.status,
185227
system_message=msg_text,
186-
# 필요하면 system_message_id=system_msg.id 이런 식으로 확장
187228
)
188229

189230
return DealStatusOut(
@@ -195,4 +236,4 @@ async def update_deal_status(
195236
postStatus=posting.status,
196237
changedBy=me.user_id,
197238
changedAt=changed_at,
198-
)
239+
)

app/utils/auth_ws.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# app/utils/auth_ws.py
2+
3+
from typing import Optional
4+
5+
from jose import jwt, JWTError
6+
from app.core.config import settings
7+
8+
9+
def decode_user_id(token: Optional[str]) -> Optional[int]:
10+
if not token:
11+
return None
12+
try:
13+
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALG])
14+
sub = payload.get("sub")
15+
return int(sub) if sub is not None else None
16+
except JWTError:
17+
return None

0 commit comments

Comments
 (0)