from django.contrib.auth import get_user_model from django.contrib.auth.models import Group, Permission from django.db import transaction from rest_framework import serializers from drf_spectacular.utils import extend_schema_field from basic_info.models import UserProfile User = get_user_model() class CorePermissionSerializer(serializers.ModelSerializer): app_label = serializers.CharField(source="content_type.app_label", read_only=True) model = serializers.CharField(source="content_type.model", read_only=True) full_code = serializers.SerializerMethodField() class Meta: model = Permission fields = [ "id", "name", "codename", "content_type", "app_label", "model", "full_code", ] read_only_fields = fields def get_full_code(self, obj) -> str: return f"{obj.content_type.app_label}.{obj.codename}" class CoreGroupSerializer(serializers.ModelSerializer): permissions = serializers.PrimaryKeyRelatedField( many=True, queryset=Permission.objects.select_related("content_type").all(), required=False, ) permission_details = CorePermissionSerializer( source="permissions", many=True, read_only=True, ) class Meta: model = Group fields = ["id", "name", "permissions", "permission_details"] class CoreUserSerializer(serializers.ModelSerializer): groups = serializers.PrimaryKeyRelatedField( many=True, queryset=Group.objects.all(), required=False, ) user_permissions = serializers.PrimaryKeyRelatedField( many=True, queryset=Permission.objects.select_related("content_type").all(), required=False, ) password = serializers.CharField(write_only=True, required=False, min_length=6) merchant_id = serializers.IntegerField(source="profile.merchant_id", read_only=True) employee_id = serializers.IntegerField(source="employee.id", read_only=True) employee_name = serializers.CharField(source="employee.name", read_only=True) group_details = serializers.SerializerMethodField() permission_details = serializers.SerializerMethodField() class Meta: model = User fields = [ "id", "username", "email", "first_name", "last_name", "is_active", "is_staff", "is_superuser", "last_login", "date_joined", "merchant_id", "employee_id", "employee_name", "groups", "group_details", "user_permissions", "permission_details", "password", ] read_only_fields = [ "id", "last_login", "date_joined", "merchant_id", "employee_id", "employee_name", "group_details", "permission_details", ] @extend_schema_field(serializers.ListField(child=serializers.DictField())) def get_group_details(self, obj) -> list[dict[str, object]]: return [{"id": group.id, "name": group.name} for group in obj.groups.all()] @extend_schema_field(CorePermissionSerializer(many=True)) def get_permission_details(self, obj) -> list[dict[str, object]]: permissions = obj.user_permissions.select_related("content_type").all() return CorePermissionSerializer(permissions, many=True).data def validate_username(self, value): queryset = User.objects.filter(username=value) if self.instance is not None: queryset = queryset.exclude(pk=self.instance.pk) if queryset.exists(): raise serializers.ValidationError("用户名已存在") return value def validate(self, attrs): request = self.context.get("request") current_user = getattr(request, "user", None) target_user = self.instance if current_user is not None and target_user is not None and current_user.pk == target_user.pk: if attrs.get("is_active") is False: raise serializers.ValidationError({"is_active": "不能停用当前登录用户"}) if attrs.get("is_superuser") is False: raise serializers.ValidationError({"is_superuser": "不能取消当前登录用户的 superuser 权限"}) return attrs def create(self, validated_data): groups = validated_data.pop("groups", []) user_permissions = validated_data.pop("user_permissions", []) password = validated_data.pop("password", None) merchant = self.context["merchant"] with transaction.atomic(): user = User(**validated_data) if password: user.set_password(password) else: user.set_unusable_password() user.save() if groups: user.groups.set(groups) if user_permissions: user.user_permissions.set(user_permissions) UserProfile.objects.create(user=user, merchant=merchant) return user def update(self, instance, validated_data): groups = validated_data.pop("groups", None) user_permissions = validated_data.pop("user_permissions", None) password = validated_data.pop("password", None) with transaction.atomic(): for attr, value in validated_data.items(): setattr(instance, attr, value) if password: instance.set_password(password) instance.save() if groups is not None: instance.groups.set(groups) if user_permissions is not None: instance.user_permissions.set(user_permissions) return instance