community
This commit is contained in:
118
backend/community/views.py
Normal file
118
backend/community/views.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from rest_framework import viewsets, status, mixins, parsers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import serializers
|
||||
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from shop.models import WeChatUser
|
||||
from .models import Activity, ActivitySignup, Topic, Reply, TopicMedia
|
||||
from .serializers import ActivitySerializer, ActivitySignupSerializer, TopicSerializer, ReplySerializer, TopicMediaSerializer
|
||||
|
||||
def get_current_wechat_user(request):
|
||||
"""
|
||||
根据 Authorization 头获取当前微信用户 (复用 shop app 的逻辑)
|
||||
"""
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if not auth_header or not auth_header.startswith('Bearer '):
|
||||
return None
|
||||
token = auth_header.split(' ')[1]
|
||||
signer = TimestampSigner()
|
||||
try:
|
||||
# 签名包含 openid
|
||||
openid = signer.unsign(token, max_age=86400 * 30) # 30天有效
|
||||
return WeChatUser.objects.filter(openid=openid).first()
|
||||
except (BadSignature, SignatureExpired):
|
||||
return None
|
||||
|
||||
class ActivityViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""
|
||||
社区活动接口
|
||||
"""
|
||||
queryset = Activity.objects.filter(is_active=True).order_by('-created_at')
|
||||
serializer_class = ActivitySerializer
|
||||
|
||||
@extend_schema(summary="报名活动")
|
||||
@action(detail=True, methods=['post'])
|
||||
def signup(self, request, pk=None):
|
||||
user = get_current_wechat_user(request)
|
||||
if not user:
|
||||
return Response({'error': '请先登录'}, status=401)
|
||||
|
||||
activity = self.get_object()
|
||||
|
||||
# Check if already signed up
|
||||
if ActivitySignup.objects.filter(activity=activity, user=user).exists():
|
||||
return Response({'error': '您已报名该活动'}, status=400)
|
||||
|
||||
if activity.signups.count() >= activity.max_participants:
|
||||
return Response({'error': '活动名额已满'}, status=400)
|
||||
|
||||
signup = ActivitySignup.objects.create(activity=activity, user=user)
|
||||
serializer = ActivitySignupSerializer(signup)
|
||||
return Response(serializer.data, status=201)
|
||||
|
||||
@extend_schema(summary="我的报名记录")
|
||||
@action(detail=False, methods=['get'])
|
||||
def my_signups(self, request):
|
||||
user = get_current_wechat_user(request)
|
||||
if not user:
|
||||
return Response({'error': '请先登录'}, status=401)
|
||||
signups = ActivitySignup.objects.filter(user=user).order_by('-signup_time')
|
||||
serializer = ActivitySignupSerializer(signups, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
class TopicViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
技术论坛帖子接口
|
||||
"""
|
||||
queryset = Topic.objects.all()
|
||||
serializer_class = TopicSerializer
|
||||
|
||||
def perform_create(self, serializer):
|
||||
user = get_current_wechat_user(self.request)
|
||||
# Auth check is done in create or permission, but here we need user for save
|
||||
if user:
|
||||
serializer.save(author=user)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
user = get_current_wechat_user(request)
|
||||
if not user:
|
||||
return Response({'error': '请先登录'}, status=401)
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
class ReplyViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
帖子回复接口
|
||||
"""
|
||||
queryset = Reply.objects.all()
|
||||
serializer_class = ReplySerializer
|
||||
|
||||
def perform_create(self, serializer):
|
||||
user = get_current_wechat_user(self.request)
|
||||
if user:
|
||||
serializer.save(author=user)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
user = get_current_wechat_user(request)
|
||||
if not user:
|
||||
return Response({'error': '请先登录'}, status=401)
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
class TopicMediaViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin):
|
||||
"""
|
||||
论坛多媒体资源上传接口
|
||||
"""
|
||||
queryset = TopicMedia.objects.all()
|
||||
serializer_class = TopicMediaSerializer
|
||||
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
|
||||
|
||||
@extend_schema(summary="上传媒体文件 (返回URL用于Markdown)")
|
||||
def create(self, request, *args, **kwargs):
|
||||
user = get_current_wechat_user(request)
|
||||
if not user:
|
||||
return Response({'error': '请先登录'}, status=401)
|
||||
|
||||
# 允许上传时不关联 Topic (发帖前上传),或后续关联
|
||||
# 主要是返回 url
|
||||
return super().create(request, *args, **kwargs)
|
||||
Reference in New Issue
Block a user