163 lines
5.3 KiB
Python
163 lines
5.3 KiB
Python
"""
|
|
Notifications API routes.
|
|
"""
|
|
from typing import List, Optional
|
|
import csv
|
|
from datetime import datetime
|
|
from ninja import Router
|
|
from ninja_jwt.authentication import JWTAuth
|
|
from ninja.pagination import paginate, PageNumberPagination
|
|
from django.shortcuts import get_object_or_404
|
|
from django.http import HttpResponse
|
|
from django.utils import timezone
|
|
|
|
from .models import Notification
|
|
from .utils import get_notification_preference
|
|
from .schemas import (
|
|
NotificationOut,
|
|
UnreadCountOut,
|
|
MessageOut,
|
|
NotificationPreferenceOut,
|
|
NotificationPreferenceIn,
|
|
)
|
|
|
|
router = Router()
|
|
|
|
|
|
@router.get("/", response=List[NotificationOut], auth=JWTAuth())
|
|
@paginate(PageNumberPagination, page_size=20)
|
|
def list_notifications(
|
|
request,
|
|
is_read: Optional[bool] = None,
|
|
type: Optional[str] = None,
|
|
start: Optional[datetime] = None,
|
|
end: Optional[datetime] = None,
|
|
):
|
|
"""Get current user's notifications."""
|
|
queryset = Notification.objects.filter(user=request.auth)
|
|
|
|
if is_read is not None:
|
|
queryset = queryset.filter(is_read=is_read)
|
|
if type:
|
|
queryset = queryset.filter(type=type)
|
|
if start:
|
|
queryset = queryset.filter(created_at__gte=start)
|
|
if end:
|
|
queryset = queryset.filter(created_at__lte=end)
|
|
|
|
return [
|
|
NotificationOut(
|
|
id=n.id,
|
|
user_id=n.user_id,
|
|
type=n.type,
|
|
title=n.title,
|
|
content=n.content,
|
|
related_id=n.related_id,
|
|
related_type=n.related_type,
|
|
is_read=n.is_read,
|
|
created_at=n.created_at,
|
|
)
|
|
for n in queryset
|
|
]
|
|
|
|
|
|
@router.get("/preferences/", response=NotificationPreferenceOut, auth=JWTAuth())
|
|
def get_preferences(request):
|
|
"""Get current user's notification preferences."""
|
|
preference = get_notification_preference(request.auth)
|
|
return NotificationPreferenceOut(
|
|
user_id=preference.user_id,
|
|
enable_bounty=preference.enable_bounty,
|
|
enable_price_alert=preference.enable_price_alert,
|
|
enable_system=preference.enable_system,
|
|
updated_at=preference.updated_at,
|
|
)
|
|
|
|
|
|
@router.patch("/preferences/", response=NotificationPreferenceOut, auth=JWTAuth())
|
|
def update_preferences(request, data: NotificationPreferenceIn):
|
|
"""Update notification preferences."""
|
|
preference = get_notification_preference(request.auth)
|
|
update_data = data.dict(exclude_unset=True)
|
|
for key, value in update_data.items():
|
|
setattr(preference, key, value)
|
|
preference.save()
|
|
return NotificationPreferenceOut(
|
|
user_id=preference.user_id,
|
|
enable_bounty=preference.enable_bounty,
|
|
enable_price_alert=preference.enable_price_alert,
|
|
enable_system=preference.enable_system,
|
|
updated_at=preference.updated_at,
|
|
)
|
|
|
|
|
|
@router.get("/unread-count/", response=UnreadCountOut, auth=JWTAuth())
|
|
def get_unread_count(request):
|
|
"""Get count of unread notifications."""
|
|
count = Notification.objects.filter(user=request.auth, is_read=False).count()
|
|
return UnreadCountOut(count=count)
|
|
|
|
|
|
@router.get("/export/", auth=JWTAuth())
|
|
def export_notifications_csv(request):
|
|
"""Export current user's notifications to CSV."""
|
|
notifications = Notification.objects.filter(user=request.auth).order_by("-created_at")
|
|
response = HttpResponse(content_type="text/csv; charset=utf-8")
|
|
filename = f'notifications_{timezone.now().strftime("%Y%m%d_%H%M%S")}.csv'
|
|
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
|
response.write("\ufeff")
|
|
|
|
writer = csv.writer(response)
|
|
writer.writerow(["created_at", "type", "title", "content", "is_read"])
|
|
for notification in notifications:
|
|
writer.writerow(
|
|
[
|
|
notification.created_at.isoformat(),
|
|
notification.type,
|
|
notification.title,
|
|
notification.content or "",
|
|
"true" if notification.is_read else "false",
|
|
]
|
|
)
|
|
|
|
return response
|
|
|
|
|
|
@router.post("/{notification_id}/read/", response=MessageOut, auth=JWTAuth())
|
|
def mark_as_read(request, notification_id: int):
|
|
"""Mark a notification as read."""
|
|
notification = get_object_or_404(
|
|
Notification,
|
|
id=notification_id,
|
|
user=request.auth
|
|
)
|
|
notification.is_read = True
|
|
notification.save()
|
|
return MessageOut(message="已标记为已读", success=True)
|
|
|
|
|
|
@router.post("/read-all/", response=MessageOut, auth=JWTAuth())
|
|
def mark_all_as_read(request):
|
|
"""Mark all notifications as read."""
|
|
Notification.objects.filter(user=request.auth, is_read=False).update(is_read=True)
|
|
return MessageOut(message="已全部标记为已读", success=True)
|
|
|
|
|
|
@router.delete("/{notification_id}", response=MessageOut, auth=JWTAuth())
|
|
def delete_notification(request, notification_id: int):
|
|
"""Delete a notification."""
|
|
notification = get_object_or_404(
|
|
Notification,
|
|
id=notification_id,
|
|
user=request.auth
|
|
)
|
|
notification.delete()
|
|
return MessageOut(message="通知已删除", success=True)
|
|
|
|
|
|
@router.delete("/", response=MessageOut, auth=JWTAuth())
|
|
def delete_all_read(request):
|
|
"""Delete all read notifications."""
|
|
Notification.objects.filter(user=request.auth, is_read=True).delete()
|
|
return MessageOut(message="已删除所有已读通知", success=True)
|