aifeilong 38ec52abf5 Add STAR International API apps and wire production Postgres defaults.
Introduce content/cms/accounts modules with DRF routes, and point default DB settings at the official starintldb instance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 17:08:01 +08:00

165 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.contrib.auth.models import User
from django.db import transaction
from rest_framework import serializers
from .models import Member
from .phone import normalize_phone
class StaffUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False, allow_blank=True)
class Meta:
model = User
fields = [
"id",
"username",
"first_name",
"email",
"is_superuser",
"is_active",
"last_login",
"date_joined",
"password",
]
read_only_fields = ["last_login", "date_joined"]
def create(self, validated_data):
password = validated_data.pop("password", None) or ""
if not password:
raise serializers.ValidationError({"password": "新建时密码必填"})
user = User(
username=validated_data["username"],
first_name=validated_data.get("first_name", ""),
email=validated_data.get("email", ""),
is_superuser=validated_data.get("is_superuser", False),
is_active=validated_data.get("is_active", True),
is_staff=True,
)
user.set_password(password)
user.save()
return user
def update(self, instance, validated_data):
password = validated_data.pop("password", None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.is_staff = True
if password:
instance.set_password(password)
instance.save()
return instance
def _ensure_member_user(member, phone, password=None, name=""):
"""为会员确保绑定非 staff 的 User;手机号作为 username。"""
if not phone:
return member
user = member.user
if user is None:
# 复用同名非 staff 账号,避免唯一约束冲突
user = User.objects.filter(username=phone, is_staff=False).first()
if user is None:
user = User(username=phone, is_staff=False, is_active=True)
if password:
user.set_password(password)
else:
user.set_unusable_password()
user.save()
member.user = user
else:
if user.username != phone:
if User.objects.filter(username=phone).exclude(pk=user.pk).exists():
raise serializers.ValidationError({"phone": "该手机号已被占用"})
user.username = phone
if password:
user.set_password(password)
user.is_staff = False
user.is_active = not member.is_disabled
user.save()
if name and not user.first_name:
user.first_name = name
user.save(update_fields=["first_name"])
return member
class MemberSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False, allow_blank=True)
class Meta:
model = Member
fields = [
"id",
"name",
"phone",
"organize",
"is_vip",
"last_login_at",
"is_disabled",
"password",
"created_at",
"updated_at",
]
read_only_fields = ["last_login_at", "created_at", "updated_at"]
def validate_phone(self, value):
# 更新时允许留空(不改手机号);新建在 create 中再强制必填
if value in (None, "") and self.instance:
return self.instance.phone
phone = normalize_phone(value, required=not bool(self.instance))
if not phone:
return phone
qs = Member.objects.filter(phone=phone)
if self.instance:
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
raise serializers.ValidationError("该手机号已被注册")
return phone
@transaction.atomic
def create(self, validated_data):
password = validated_data.pop("password", None) or ""
phone = validated_data.get("phone") or ""
if not phone:
raise serializers.ValidationError({"phone": "手机号必填"})
if not password:
raise serializers.ValidationError({"password": "新建时密码必填"})
member = Member(**validated_data)
member.save()
_ensure_member_user(member, phone, password=password, name=member.name)
member.save(update_fields=["user", "updated_at"])
return member
@transaction.atomic
def update(self, instance, validated_data):
password = validated_data.pop("password", None) or ""
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
if instance.phone:
_ensure_member_user(
instance,
instance.phone,
password=password or None,
name=instance.name,
)
instance.save(update_fields=["user", "updated_at"])
elif password:
raise serializers.ValidationError({"phone": "设置密码前需填写手机号"})
return instance
class MemberPublicSerializer(serializers.ModelSerializer):
"""前台登录/注册返回的会员信息(不含禁用标记写入)。"""
class Meta:
model = Member
fields = [
"id",
"name",
"phone",
"organize",
"is_vip",
"last_login_at",
]