from django.db import IntegrityError from .models import ( EncryptionConfigurationError, ImmichIntegration, UserAISettings, UserAPIKey, UserRecommendationPreferenceProfile, ) from rest_framework import serializers class ImmichIntegrationSerializer(serializers.ModelSerializer): class Meta: model = ImmichIntegration fields = "__all__" read_only_fields = ["id", "user"] def to_representation(self, instance): representation = super().to_representation(instance) representation.pop("user", None) return representation class UserAPIKeySerializer(serializers.ModelSerializer): api_key = serializers.CharField(write_only=True, required=True, allow_blank=False) masked_api_key = serializers.CharField(read_only=True) class Meta: model = UserAPIKey fields = [ "id", "provider", "api_key", "masked_api_key", "created_at", "updated_at", ] read_only_fields = ["id", "masked_api_key", "created_at", "updated_at"] def validate_provider(self, value): return (value or "").strip().lower() def create(self, validated_data): api_key = validated_data.pop("api_key") user = self.context["request"].user provider = validated_data.get("provider") try: instance, _ = UserAPIKey.objects.get_or_create( user=user, provider=provider, defaults={"encrypted_api_key": ""}, ) instance.set_api_key(api_key) except EncryptionConfigurationError as exc: raise serializers.ValidationError({"api_key": str(exc)}) from exc except IntegrityError: # Defensive retry: in highly concurrent requests a competing create can # still race. Fall back to updating the existing row instead of 500. instance = UserAPIKey.objects.get(user=user, provider=provider) try: instance.set_api_key(api_key) except EncryptionConfigurationError as exc: raise serializers.ValidationError({"api_key": str(exc)}) from exc instance.save(update_fields=["encrypted_api_key", "updated_at"]) return instance def update(self, instance, validated_data): api_key = validated_data.pop("api_key", None) for attr, value in validated_data.items(): setattr(instance, attr, value) if api_key is not None: try: instance.set_api_key(api_key) except EncryptionConfigurationError as exc: raise serializers.ValidationError({"api_key": str(exc)}) from exc instance.save() return instance def to_representation(self, instance): representation = super().to_representation(instance) representation.pop("api_key", None) return representation class UserRecommendationPreferenceProfileSerializer(serializers.ModelSerializer): class Meta: model = UserRecommendationPreferenceProfile fields = [ "id", "cuisines", "interests", "trip_style", "notes", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] class UserAISettingsSerializer(serializers.ModelSerializer): class Meta: model = UserAISettings fields = [ "id", "preferred_provider", "preferred_model", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"]