Files
AutonetSellCar/backend/app/api/notification.py
AutonetSellCar Deploy 1f0dcb1ddb Initial commit: AutonetSellCar platform with deployment system
- Frontend: Next.js 14 with TypeScript
- Backend: FastAPI with SQLAlchemy
- Agent: Carmodoo sync agent
- Deployment: Docker Compose based staging/production setup
- Scripts: Automated deployment with rollback support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:24:39 +09:00

364 lines
11 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import desc
from datetime import datetime
from typing import List, Optional
from ..database import get_db
from ..models import User, Notification
from ..schemas.notification import (
NotificationCreate, NotificationResponse,
NotificationListResponse, NotificationMarkRead
)
from .auth import get_current_user
router = APIRouter(prefix="/notifications", tags=["notifications"])
# =====================
# Helper Functions
# =====================
def create_notification(
db: Session,
user_id: int,
notification_type: str,
title: str,
message: str,
link: Optional[str] = None,
related_id: Optional[int] = None,
related_type: Optional[str] = None
) -> Notification:
"""Create a new notification"""
notification = Notification(
user_id=user_id,
notification_type=notification_type,
title=title,
message=message,
link=link,
related_id=related_id,
related_type=related_type
)
db.add(notification)
db.commit()
db.refresh(notification)
return notification
def notify_vehicle_recommended(db: Session, user_id: int, request_id: int, vehicle_count: int):
"""Notify user when vehicles are recommended for their request"""
return create_notification(
db=db,
user_id=user_id,
notification_type="vehicle_recommended",
title="차량 추천 완료",
message=f"{vehicle_count}대의 차량이 추천되었습니다. 지금 확인해보세요!",
link=f"/my-request",
related_id=request_id,
related_type="vehicle_request"
)
def notify_shipping_update(db: Session, user_id: int, vehicle_id: int, status: int, car_name: str):
"""Notify user when shipping status changes"""
status_names = {
1: "구매완료",
2: "인천항 도착",
3: "텐진항 도착",
4: "자먼우드 도착",
5: "울란바토르 도착",
6: "통관 진행중",
7: "배송완료"
}
status_name = status_names.get(status, f"상태 {status}")
return create_notification(
db=db,
user_id=user_id,
notification_type="shipping_update",
title="배송 상태 업데이트",
message=f"{car_name}: {status_name}",
link=f"/find-my-car",
related_id=vehicle_id,
related_type="purchased_vehicle"
)
def notify_withdrawal_processed(db: Session, user_id: int, withdrawal_id: int, status: str, amount: float):
"""Notify user when withdrawal request is processed"""
status_messages = {
"approved": f"출금 신청이 승인되었습니다. {amount:,.0f}원이 곧 입금됩니다.",
"completed": f"출금 완료! {amount:,.0f}원이 입금되었습니다.",
"rejected": "출금 신청이 거부되었습니다. 관리자에게 문의해주세요."
}
return create_notification(
db=db,
user_id=user_id,
notification_type="withdrawal_processed",
title="출금 처리 알림",
message=status_messages.get(status, "출금 상태가 변경되었습니다."),
link="/withdrawal",
related_id=withdrawal_id,
related_type="withdrawal"
)
def notify_referral_reward(db: Session, user_id: int, reward_amount: float, referred_name: str):
"""Notify user when they receive referral reward"""
return create_notification(
db=db,
user_id=user_id,
notification_type="referral_reward",
title="레퍼럴 보상 적립",
message=f"{referred_name}님의 충전으로 {reward_amount:,.0f}원이 적립되었습니다!",
link="/withdrawal",
related_type="referral"
)
def notify_dealer_approved(db: Session, user_id: int, dealer_code: str):
"""Notify user when dealer application is approved"""
return create_notification(
db=db,
user_id=user_id,
notification_type="dealer_approved",
title="딜러 승인 완료",
message=f"딜러 승인이 완료되었습니다! 딜러 코드: {dealer_code}",
link="/dealer/my-card",
related_type="dealer"
)
def notify_dealer_rejected(db: Session, user_id: int, reason: str):
"""Notify user when dealer application is rejected"""
return create_notification(
db=db,
user_id=user_id,
notification_type="dealer_rejected",
title="딜러 신청 거부",
message=f"딜러 신청이 거부되었습니다. 사유: {reason}",
link="/dealer/apply",
related_type="dealer"
)
def notify_share_purchased(db: Session, user_id: int, share_id: int, reward_amount: float, car_name: str):
"""Notify user when their shared vehicle is purchased"""
return create_notification(
db=db,
user_id=user_id,
notification_type="share_purchased",
title="공유 차량 판매 완료",
message=f"{car_name} 판매 완료! 리워드 {reward_amount:,.0f}원이 적립되었습니다.",
link="/withdrawal",
related_id=share_id,
related_type="vehicle_share"
)
def notify_payment_confirmed(db: Session, user_id: int, charge_id: int, amount: float, cc_amount: int):
"""Notify user when payment is confirmed"""
return create_notification(
db=db,
user_id=user_id,
notification_type="payment_confirmed",
title="결제 확인 완료",
message=f"결제가 확인되었습니다! ${amount:.2f}{cc_amount} CC가 충전되었습니다.",
link="/charge",
related_id=charge_id,
related_type="charge"
)
def notify_inquiry_reply(db: Session, user_id: int, inquiry_id: int, subject: str = None):
"""Notify user when admin replies to their inquiry"""
return create_notification(
db=db,
user_id=user_id,
notification_type="inquiry_reply",
title="문의 답변 등록",
message=f"문의에 답변이 등록되었습니다." + (f" ({subject})" if subject else ""),
link=f"/my-inquiries/{inquiry_id}",
related_id=inquiry_id,
related_type="inquiry"
)
def notify_system(db: Session, user_id: int, title: str, message: str, link: Optional[str] = None):
"""Send a general system notification to a user"""
return create_notification(
db=db,
user_id=user_id,
notification_type="system",
title=title,
message=message,
link=link
)
# =====================
# User Endpoints
# =====================
@router.get("/", response_model=NotificationListResponse)
def get_notifications(
page: int = 1,
page_size: int = 20,
unread_only: bool = False,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get user's notifications"""
query = db.query(Notification).filter(Notification.user_id == current_user.id)
if unread_only:
query = query.filter(Notification.is_read == False)
total = query.count()
unread_count = db.query(Notification).filter(
Notification.user_id == current_user.id,
Notification.is_read == False
).count()
notifications = query.order_by(desc(Notification.created_at)) \
.offset((page - 1) * page_size) \
.limit(page_size) \
.all()
return NotificationListResponse(
notifications=[NotificationResponse.model_validate(n) for n in notifications],
unread_count=unread_count,
total=total
)
@router.get("/unread-count")
def get_unread_count(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get count of unread notifications"""
count = db.query(Notification).filter(
Notification.user_id == current_user.id,
Notification.is_read == False
).count()
return {"unread_count": count}
@router.post("/mark-read")
def mark_as_read(
data: NotificationMarkRead,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Mark notifications as read"""
notifications = db.query(Notification).filter(
Notification.id.in_(data.notification_ids),
Notification.user_id == current_user.id
).all()
for notification in notifications:
notification.is_read = True
notification.read_at = datetime.utcnow()
db.commit()
return {"message": f"Marked {len(notifications)} notifications as read"}
@router.post("/mark-all-read")
def mark_all_as_read(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Mark all notifications as read"""
count = db.query(Notification).filter(
Notification.user_id == current_user.id,
Notification.is_read == False
).update({
"is_read": True,
"read_at": datetime.utcnow()
})
db.commit()
return {"message": f"Marked {count} notifications as read"}
@router.delete("/{notification_id}")
def delete_notification(
notification_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Delete a notification"""
notification = db.query(Notification).filter(
Notification.id == notification_id,
Notification.user_id == current_user.id
).first()
if not notification:
raise HTTPException(status_code=404, detail="Notification not found")
db.delete(notification)
db.commit()
return {"message": "Notification deleted"}
# =====================
# Admin Endpoints
# =====================
@router.post("/admin/send")
def admin_send_notification(
notification_data: NotificationCreate,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Send notification to a user"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
notification = create_notification(
db=db,
user_id=notification_data.user_id,
notification_type=notification_data.notification_type,
title=notification_data.title,
message=notification_data.message,
link=notification_data.link,
related_id=notification_data.related_id,
related_type=notification_data.related_type
)
return NotificationResponse.model_validate(notification)
@router.post("/admin/send-all")
def admin_send_to_all(
title: str,
message: str,
link: Optional[str] = None,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Send notification to all users"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
users = db.query(User).filter(User.is_active == True).all()
for user in users:
create_notification(
db=db,
user_id=user.id,
notification_type="system",
title=title,
message=message,
link=link
)
return {"message": f"Sent notification to {len(users)} users"}