| 47 | |
| 48 | # 🔹 Fix for User serialization |
| 49 | class UserSerializer(serializers.ModelSerializer): |
| 50 | password = serializers.CharField(write_only=True, required=False) |
| 51 | channel_profiles = serializers.PrimaryKeyRelatedField( |
| 52 | queryset=ChannelProfile.objects.all(), many=True, required=False |
| 53 | ) |
| 54 | api_key = serializers.CharField(read_only=True, allow_null=True) |
| 55 | |
| 56 | class Meta: |
| 57 | model = User |
| 58 | fields = [ |
| 59 | "id", |
| 60 | "username", |
| 61 | "api_key", |
| 62 | "email", |
| 63 | "user_level", |
| 64 | "password", |
| 65 | "channel_profiles", |
| 66 | "custom_properties", |
| 67 | "avatar_config", |
| 68 | "stream_limit", |
| 69 | "is_staff", |
| 70 | "is_superuser", |
| 71 | "last_login", |
| 72 | "date_joined", |
| 73 | "first_name", |
| 74 | "last_name", |
| 75 | ] |
| 76 | |
| 77 | def validate_custom_properties(self, value): |
| 78 | """Validate custom_properties structure and size.""" |
| 79 | if value is None: |
| 80 | return {} |
| 81 | if not isinstance(value, dict): |
| 82 | raise serializers.ValidationError("custom_properties must be a dictionary") |
| 83 | |
| 84 | # Size limit check |
| 85 | try: |
| 86 | if len(json.dumps(value)) > MAX_CUSTOM_PROPS_SIZE: |
| 87 | raise serializers.ValidationError( |
| 88 | f"custom_properties exceeds maximum size of {MAX_CUSTOM_PROPS_SIZE} bytes" |
| 89 | ) |
| 90 | except (TypeError, ValueError): |
| 91 | raise serializers.ValidationError("custom_properties contains non-serializable data") |
| 92 | |
| 93 | # Validate navOrder if present |
| 94 | if 'navOrder' in value: |
| 95 | validate_nav_array(value['navOrder'], 'navOrder') |
| 96 | |
| 97 | # Validate hiddenNav if present |
| 98 | if 'hiddenNav' in value: |
| 99 | validate_nav_array(value['hiddenNav'], 'hiddenNav') |
| 100 | |
| 101 | return value |
| 102 | |
| 103 | def create(self, validated_data): |
| 104 | channel_profiles = validated_data.pop("channel_profiles", []) |
| 105 | |
| 106 | user = User(**validated_data) |