Files
Hulumath-Web/backend/accounts/views.py
T
Jacky 1f98f7152d
CI / test (push) Failing after 1m31s
v0.2 Preview: Construction Plan.
2026-08-08 21:25:27 +08:00

112 lines
3.8 KiB
Python

from django.contrib.auth import authenticate, login, logout
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from .migration_service import apply_visitor_migration
from .models import UserSession, VisitorMigration
from .serializers import RegisterSerializer, UserSerializer
def client_ip(request):
forwarded = request.META.get("HTTP_X_FORWARDED_FOR")
return forwarded.split(",")[0].strip() if forwarded else request.META.get("REMOTE_ADDR")
class RegisterView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
serializer = RegisterSerializer(
data=request.data,
context={"ip_address": client_ip(request)},
)
serializer.is_valid(raise_exception=True)
user = serializer.save()
login(request, user)
self._record_session(request, user)
payload = UserSerializer(user).data
payload["visitor_migration_pending"] = hasattr(user, "visitor_migration")
return Response(payload, status=status.HTTP_201_CREATED)
@staticmethod
def _record_session(request, user):
if not request.session.session_key:
request.session.save()
UserSession.objects.update_or_create(
session_key=request.session.session_key,
defaults={
"user": user,
"user_agent": request.headers.get("User-Agent", "")[:300],
"ip_address": client_ip(request),
},
)
class LoginView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
user = authenticate(
request,
username=request.data.get("username", ""),
password=request.data.get("password", ""),
)
if user is None or not user.is_active:
return Response(
{"error": {"code": "invalid_credentials", "message": "用户名或密码错误"}},
status=status.HTTP_400_BAD_REQUEST,
)
login(request, user)
RegisterView._record_session(request, user)
return Response(UserSerializer(user).data)
class LogoutView(APIView):
def post(self, request):
if request.session.session_key:
UserSession.objects.filter(session_key=request.session.session_key).delete()
logout(request)
return Response(status=status.HTTP_204_NO_CONTENT)
class MeView(APIView):
def get(self, request):
return Response(UserSerializer(request.user).data)
def patch(self, request):
serializer = UserSerializer(request.user, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
class VisitorMigrationView(APIView):
def get(self, request):
migration = VisitorMigration.objects.filter(user=request.user).first()
if migration is None:
return Response({"pending": False, "summary": {}})
return Response(
{
"pending": migration.status == VisitorMigration.Status.PENDING,
"status": migration.status,
"summary": migration.summary,
}
)
def post(self, request):
migration = VisitorMigration.objects.filter(user=request.user).first()
if migration is None:
return Response(
{"error": {"code": "no_visitor_data", "message": "没有待迁移的游客数据"}},
status=status.HTTP_404_NOT_FOUND,
)
migration = apply_visitor_migration(request.user)
return Response(
{
"pending": False,
"status": migration.status,
"summary": migration.summary,
}
)