from rest_framework import serializers from .models import User, Enterprise, Role, EnterpriseMember, Permission class UserSerializer(serializers.ModelSerializer): roles = serializers.ReadOnlyField() permissions = serializers.SerializerMethodField() opc_certification = serializers.SerializerMethodField() enterprise_info = serializers.SerializerMethodField() class Meta: model = User fields = ['id', 'username', 'phone', 'email', 'nickname', 'avatar_url', 'face_url', 'bio', 'location', 'status', 'is_active', 'created_at', 'roles', 'permissions', 'is_staff', 'is_superuser', 'rating', 'completed_tasks', 'opc_certification', 'enterprise_info', 'is_recommended', 'recommend_priority'] read_only_fields = ['id', 'status', 'is_active', 'created_at', 'roles', 'permissions', 'is_staff', 'is_superuser'] def get_enterprise_info(self, obj): if 'ENTERPRISE' in obj.roles: from .models import Enterprise, EnterpriseMember ent = Enterprise.objects.filter(user=obj).first() if ent: return {'company_name': ent.company_name, 'role': 'OWNER'} member = EnterpriseMember.objects.filter(user=obj).first() if member: return {'company_name': member.enterprise.company_name, 'role': member.role} return None def get_opc_certification(self, obj): if 'OPC_USER' in obj.roles: from opc_cert.models import OpcCertification from opc_cert.serializers import OpcCertificationSerializer cert = OpcCertification.objects.filter(user=obj, status='APPROVED').first() if cert: return OpcCertificationSerializer(cert).data return None def get_permissions(self, obj): if obj.is_superuser: return ['*'] from .models import RolePermission perms = RolePermission.objects.filter(role__userrole__user=obj).values_list('permission__code', flat=True).distinct() return list(perms) def validate(self, attrs): # Normalize empty strings to None to avoid unique constraint issues for field in ['phone', 'email']: if field in attrs and attrs[field] == '': attrs[field] = None return attrs class RoleSerializer(serializers.ModelSerializer): permission_ids = serializers.SerializerMethodField() class Meta: model = Role fields = '__all__' def get_permission_ids(self, obj): return list(obj.role_permissions.values_list('permission_id', flat=True).distinct().values_list('permission_id', flat=True)) def to_representation(self, instance): data = super().to_representation(instance) # Ensure permission_ids are strings for frontend comparison data['permission_ids'] = [str(pid) for pid in data.get('permission_ids', [])] return data class PermissionSerializer(serializers.ModelSerializer): class Meta: model = Permission fields = '__all__' class EnterpriseMemberSerializer(serializers.ModelSerializer): user_details = UserSerializer(source='user', read_only=True) class Meta: model = EnterpriseMember fields = ['id', 'user', 'user_details', 'role', 'joined_at'] read_only_fields = ['id', 'joined_at'] import re from django.core.validators import EmailValidator from rest_framework.exceptions import ValidationError class RegisterSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, min_length=6) username = serializers.CharField( error_messages={ 'unique': '该用户名已被占用,请尝试其他名称' } ) phone = serializers.CharField( required=False, allow_blank=True, error_messages={ 'unique': '该手机号已注册,请直接登录' } ) email = serializers.EmailField( required=False, allow_blank=True, error_messages={ 'unique': '该邮箱已注册,请尝试其他邮箱' } ) avatar_url = serializers.CharField(required=False, allow_blank=True) class Meta: model = User fields = ['username', 'phone', 'email', 'password', 'nickname', 'avatar_url'] def validate_phone(self, value): if value: if not re.match(r'^1[3-9]\d{9}$', value): raise ValidationError('请输入有效的11位手机号') if User.objects.filter(phone=value, is_deleted=False).exists(): raise ValidationError('该手机号已注册,请直接登录') return value def validate_email(self, value): if value: if User.objects.filter(email=value, is_deleted=False).exists(): raise ValidationError('该邮箱已注册,请尝试其他邮箱') return value def validate_username(self, value): if User.objects.filter(username=value, is_deleted=False).exists(): raise ValidationError('该用户名已被占用,请尝试其他名称') return value def create(self, validated_data): phone = validated_data.get('phone') if phone == '': phone = None email = validated_data.get('email') if email == '': email = None user = User.objects.create_user( username=validated_data['username'], phone=phone, email=email, password=validated_data['password'], nickname=validated_data.get('nickname'), avatar_url=validated_data.get('avatar_url', '') ) # Auto-assign USER role from .models import Role, UserRole user_role, _ = Role.objects.get_or_create(code='USER', defaults={'name': '普通用户'}) UserRole.objects.get_or_create(user=user, role=user_role) return user class AdminUserCreateSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, min_length=6) email = serializers.EmailField(required=False, allow_blank=True) username = serializers.CharField( error_messages={'unique': '该用户名已被占用'} ) phone = serializers.CharField( required=False, allow_blank=True, error_messages={'unique': '该手机号已注册'} ) class Meta: model = User fields = ['username', 'phone', 'email', 'password', 'nickname'] def validate_phone(self, value): if value: if not re.match(r'^1[3-9]\d{9}$', value): raise ValidationError('请输入有效的11位手机号') if User.objects.filter(phone=value).exists(): raise ValidationError('该手机号已注册') return value def validate_email(self, value): if value: if User.objects.filter(email=value).exists(): raise ValidationError('该邮箱已注册') return value def create(self, validated_data): phone = validated_data.get('phone') if phone == '': phone = None user = User.objects.create_user( username=validated_data['username'], phone=phone, email=validated_data.get('email'), password=validated_data['password'], nickname=validated_data.get('nickname') ) # Auto-assign USER role from .models import Role, UserRole user_role, _ = Role.objects.get_or_create(code='USER', defaults={'name': '普通用户'}) UserRole.objects.get_or_create(user=user, role=user_role) return user class EnterpriseSerializer(serializers.ModelSerializer): user_details = UserSerializer(source='user', read_only=True) credit_code = serializers.CharField( error_messages={ 'unique': '该统一社会信用代码已注册,请核对信息' } ) class Meta: model = Enterprise fields = ['id', 'user', 'user_details', 'company_name', 'credit_code', 'business_license', 'contact_name', 'contact_phone', 'landline', 'contact_email', 'address', 'description', 'status', 'logo_url', 'created_at', 'updated_at'] read_only_fields = ['id', 'user', 'user_details', 'status', 'created_at', 'updated_at'] def validate_credit_code(self, value): if value: if not re.match(r'^[A-Z0-9]{18}$', value): raise ValidationError('请输入有效的18位统一社会信用代码') return value from django.db import transaction class EnterpriseRegisterSerializer(serializers.Serializer): email = serializers.EmailField() password = serializers.CharField(write_only=True, min_length=6) company_name = serializers.CharField(max_length=255) credit_code = serializers.CharField(max_length=18) business_license = serializers.CharField(required=False, allow_blank=True) logo_url = serializers.CharField(required=False, allow_blank=True) def validate_credit_code(self, value): if not re.match(r'^[A-Z0-9]{18}$', value): raise ValidationError('请输入有效的18位统一社会信用代码') if Enterprise.objects.filter(credit_code=value).exists(): raise ValidationError('该社会信用代码已注册') return value def validate_email(self, value): if User.objects.filter(email=value).exists(): raise ValidationError('该邮箱已注册') return value def create(self, validated_data): with transaction.atomic(): # 1. Create User user = User.objects.create_user( username=validated_data['email'], email=validated_data['email'], password=validated_data['password'], nickname=validated_data['company_name'], avatar_url=validated_data.get('logo_url') ) # 2. Create Enterprise enterprise = Enterprise.objects.create( user=user, company_name=validated_data['company_name'], credit_code=validated_data['credit_code'], business_license=validated_data.get('business_license', ''), logo_url=validated_data.get('logo_url') ) # 3. Assign Role from .models import Role, UserRole role, created = Role.objects.get_or_create(code='ENTERPRISE', defaults={'name': '企业用户'}) UserRole.objects.get_or_create(user=user, role=role) return enterprise class AdminEnterpriseCreateSerializer(serializers.ModelSerializer): email = serializers.EmailField(write_only=True) password = serializers.CharField(write_only=True, min_length=6) class Meta: model = Enterprise fields = ['email', 'password', 'company_name', 'credit_code', 'business_license', 'contact_name', 'contact_phone', 'contact_email', 'address', 'description', 'logo_url'] def validate_credit_code(self, value): if value: if not re.match(r'^[A-Z0-9]{18}$', value): raise ValidationError('请输入有效的18位统一社会信用代码') if Enterprise.objects.filter(credit_code=value).exists(): raise ValidationError('该社会信用代码已注册') return value def validate_email(self, value): if User.objects.filter(email=value).exists(): raise ValidationError('该邮箱已注册,无法创建企业账号') return value def create(self, validated_data): email = validated_data.pop('email') password = validated_data.pop('password') with transaction.atomic(): user = User.objects.create_user( username=email, email=email, password=password, nickname=validated_data['company_name'], avatar_url=validated_data.get('logo_url') ) enterprise = Enterprise.objects.create( user=user, status='VERIFIED', # Admins create pre-verified enterprises **validated_data ) from .models import Role, UserRole role, _ = Role.objects.get_or_create(code='ENTERPRISE', defaults={'name': '企业用户'}) UserRole.objects.get_or_create(user=user, role=role) return enterprise from django.contrib.auth import authenticate class EnterpriseLoginSerializer(serializers.Serializer): login_type = serializers.ChoiceField(choices=['ADMIN', 'EMPLOYEE'], default='ADMIN') enterprise_email = serializers.EmailField() username = serializers.CharField(required=False, allow_blank=True) password = serializers.CharField(write_only=True) def validate(self, data): login_type = data.get('login_type', 'ADMIN') enterprise_email = data.get('enterprise_email') username = data.get('username') password = data.get('password') # 1. Find enterprise try: enterprise_user = User.objects.get(email=enterprise_email) enterprise = Enterprise.objects.get(user=enterprise_user) except (User.DoesNotExist, Enterprise.DoesNotExist): raise ValidationError({'detail': '企业邮箱未注册'}) if login_type == 'ADMIN': # 2. Find and authenticate the admin if not enterprise_user.is_active or enterprise_user.is_deleted: raise ValidationError({'detail': '您的账号已被禁用,可能因为违规操作或安全风险。如有疑问请联系平台管理员。'}) if not enterprise_user.check_password(password): raise ValidationError({'detail': '管理员邮箱或密码错误'}) # Check if user is the enterprise owner user = enterprise_user else: # EMPLOYEE login if not username: raise ValidationError({'detail': '员工账号不能为空'}) namespaced_username = f"{enterprise_email}_{username}" user = User.objects.filter(username=namespaced_username).first() if not user: raise ValidationError({'detail': '员工账号未注册'}) if not user.is_active or user.is_deleted: raise ValidationError({'detail': '您的账号已被禁用,可能因为违规操作或安全风险。如有疑问请联系平台管理员。'}) if not user.check_password(password): raise ValidationError({'detail': '员工账号或密码错误'}) # Check if user is a member of the enterprise if not EnterpriseMember.objects.filter(enterprise=enterprise, user=user).exists(): raise ValidationError({'detail': '该员工不属于此企业团队'}) data['user'] = user return data class EnterpriseMemberAddSerializer(serializers.Serializer): username = serializers.CharField() password = serializers.CharField(write_only=True, min_length=6) nickname = serializers.CharField(required=False, allow_blank=True) role = serializers.ChoiceField(choices=EnterpriseMember.MemberRole.choices, default=EnterpriseMember.MemberRole.MEMBER) enterprise_id = serializers.UUIDField(required=False) def _get_enterprise(self): request_user = self.context['request'].user enterprise_id = self.initial_data.get('enterprise_id') if enterprise_id and (request_user.is_staff or request_user.is_superuser): try: return Enterprise.objects.get(id=enterprise_id) except Enterprise.DoesNotExist: raise ValidationError('指定的企业不存在') try: return Enterprise.objects.get(user=request_user) except Enterprise.DoesNotExist: raise ValidationError('当前用户没有关联的企业主体') def validate_username(self, value): enterprise = self._get_enterprise() namespaced_username = f"{enterprise.user.email}_{value}" if User.objects.filter(username=namespaced_username).exists(): raise ValidationError('该用户名已被占用') return value def create(self, validated_data): enterprise = self._get_enterprise() with transaction.atomic(): namespaced_username = f"{enterprise.user.email}_{validated_data['username']}" user = User.objects.create_user( username=namespaced_username, password=validated_data['password'], nickname=validated_data.get('nickname', validated_data['username']) ) # Assign ENTERPRISE role so they can access enterprise portal from .models import Role, UserRole role, _ = Role.objects.get_or_create(code='ENTERPRISE', defaults={'name': '企业用户'}) UserRole.objects.get_or_create(user=user, role=role) member = EnterpriseMember.objects.create( enterprise=enterprise, user=user, role=validated_data.get('role', EnterpriseMember.MemberRole.MEMBER) ) return member class ChangePasswordSerializer(serializers.Serializer): old_password = serializers.CharField(required=True) new_password = serializers.CharField(required=True, min_length=6) class PasswordResetRequestSerializer(serializers.Serializer): email = serializers.EmailField(required=True) class PasswordResetConfirmSerializer(serializers.Serializer): email = serializers.EmailField(required=True) verification_code = serializers.CharField(required=True, min_length=6, max_length=6) new_password = serializers.CharField(required=True, min_length=6)