class DraftCommentSerializer(serializers.ModelSerializer): user = SplitField( serializers.PrimaryKeyRelatedField(queryset=UserProfile.objects.all()), BaseUserSerializer()) version = SplitField( serializers.PrimaryKeyRelatedField(queryset=Version.unfiltered.all()), AddonBrowseVersionSerializer()) canned_response = SplitField( serializers.PrimaryKeyRelatedField( queryset=CannedResponse.objects.all(), required=False), CannedResponseSerializer()) class Meta: model = DraftComment fields = ('id', 'filename', 'lineno', 'comment', 'version', 'user', 'canned_response') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Set the instance for `AddonBrowseVersionSerializer` which requires # on `instance` being set correctly. self.fields['version'].output.instance = self.context['version'] def validate(self, data): if data.get('comment') and data.get('canned_response'): raise serializers.ValidationError({ 'comment': ugettext('You can\'t submit a comment if `canned_response` is ' 'defined.') }) return data
class DraftCommentSerializer(serializers.ModelSerializer): user = SplitField( serializers.PrimaryKeyRelatedField(queryset=UserProfile.objects.all()), BaseUserSerializer()) version_id = serializers.PrimaryKeyRelatedField( queryset=Version.unfiltered.all(), source='version') canned_response = SplitField( serializers.PrimaryKeyRelatedField( queryset=CannedResponse.objects.all(), required=False), CannedResponseSerializer(), allow_null=True, required=False) class Meta: model = DraftComment fields = ( 'id', 'filename', 'lineno', 'comment', 'version_id', 'user', 'canned_response' ) def get_or_default(self, key, data, default=''): """Return the value of ``key`` in ``data`` If that key is not present then return the value of ``key`` from ``self.instance`, otherwise return the ``default``. This method is a helper to simplify validation for partial updates. """ retval = data.get(key) if retval is None and self.instance is not None: retval = getattr(self.instance, key) return retval or default def validate(self, data): canned_response = self.get_or_default('canned_response', data) comment = self.get_or_default('comment', data) if comment and canned_response: raise serializers.ValidationError( {'comment': ugettext( 'You can\'t submit a comment if `canned_response` is ' 'defined.')}) if not canned_response and not comment: raise serializers.ValidationError( {'comment': ugettext( 'You can\'t submit an empty comment.')}) lineno = self.get_or_default('lineno', data) filename = self.get_or_default('filename', data) if lineno and not filename: raise serializers.ValidationError( {'comment': ugettext( 'You can\'t submit a line number without associating ' 'it to a filename.')}) return data
class DraftCommentSerializer(serializers.ModelSerializer): user = SplitField( serializers.PrimaryKeyRelatedField(queryset=UserProfile.objects.all()), BaseUserSerializer()) version = SplitField( serializers.PrimaryKeyRelatedField( queryset=Version.unfiltered.all()), VersionSerializer()) class Meta: model = DraftComment fields = ( 'id', 'filename', 'lineno', 'comment', 'version', 'user' )
class VersionSerializer(SimpleVersionSerializer): channel = ReverseChoiceField(choices=list(amo.CHANNEL_CHOICES_API.items()), read_only=True) license = SplitField( LicenseSlugSerializerField(required=False), LicenseSerializer(), ) class Meta: model = Version fields = ( 'id', 'channel', 'compatibility', 'edit_url', 'file', 'is_strict_compatibility_enabled', 'license', 'release_notes', 'reviewed', 'version', ) read_only_fields = fields def __init__(self, instance=None, data=serializers.empty, **kwargs): self.addon = kwargs.pop('addon', None) super().__init__(instance=instance, data=data, **kwargs)
class CollectionAddonSerializer(serializers.ModelSerializer): addon = SplitField( SlugOrPrimaryKeyRelatedField( # .no_cache() because django-cache-machine blows up otherwise. # Only used for writes (this is input field) so no perf concerns. queryset=Addon.objects.public().no_cache()), AddonSerializer()) notes = TranslationSerializerField(source='comments', required=False) collection = serializers.HiddenField(default=ThisCollectionDefault()) class Meta: model = CollectionAddon fields = ('addon', 'downloads', 'notes', 'collection') validators = [ UniqueTogetherValidator( queryset=CollectionAddon.objects.all(), message=_(u'This add-on already belongs to the collection'), fields=('addon', 'collection') ), ] writeable_fields = ( 'notes', ) read_only_fields = tuple(set(fields) - set(writeable_fields)) def validate(self, data): if self.partial: # addon is read_only but SplitField messes with the initialization. # DRF normally ignores updates to read_only fields, so do the same. data.pop('addon') return super(CollectionAddonSerializer, self).validate(data)
class AddonSerializer(serializers.ModelSerializer): authors = AddonDeveloperSerializer(many=True, source='listed_authors', read_only=True) categories = CategoriesSerializerField(source='all_categories', required=False) contributions_url = ContributionSerializerField(source='contributions', read_only=True) current_version = CurrentVersionSerializer(read_only=True) description = TranslationSerializerField(required=False) developer_comments = TranslationSerializerField(required=False) edit_url = serializers.SerializerMethodField() has_eula = serializers.SerializerMethodField() has_privacy_policy = serializers.SerializerMethodField() homepage = OutgoingURLTranslationField(required=False) icon_url = serializers.SerializerMethodField() icons = serializers.SerializerMethodField() is_disabled = SplitField( serializers.BooleanField(source='disabled_by_user', required=False), serializers.BooleanField(), ) is_source_public = serializers.SerializerMethodField() is_featured = serializers.SerializerMethodField() name = TranslationSerializerField(required=False, max_length=50) previews = PreviewSerializer(many=True, source='current_previews', read_only=True) promoted = PromotedAddonSerializer(read_only=True) ratings = serializers.SerializerMethodField() ratings_url = serializers.SerializerMethodField() review_url = serializers.SerializerMethodField() status = ReverseChoiceField(choices=list(amo.STATUS_CHOICES_API.items()), read_only=True) summary = TranslationSerializerField(required=False, max_length=250) support_email = EmailTranslationField(required=False) support_url = OutgoingURLTranslationField(required=False) tags = serializers.ListField( child=LazyChoiceField( choices=Tag.objects.values_list('tag_text', flat=True)), max_length=amo.MAX_TAGS, source='tag_list', required=False, ) type = ReverseChoiceField(choices=list(amo.ADDON_TYPE_CHOICES_API.items()), read_only=True) url = serializers.SerializerMethodField() version = DeveloperVersionSerializer(write_only=True) versions_url = serializers.SerializerMethodField() class Meta: model = Addon fields = ( 'id', 'authors', 'average_daily_users', 'categories', 'contributions_url', 'created', 'current_version', 'default_locale', 'description', 'developer_comments', 'edit_url', 'guid', 'has_eula', 'has_privacy_policy', 'homepage', 'icon_url', 'icons', 'is_disabled', 'is_experimental', 'is_featured', 'is_source_public', 'last_updated', 'name', 'previews', 'promoted', 'ratings', 'ratings_url', 'requires_payment', 'review_url', 'slug', 'status', 'summary', 'support_email', 'support_url', 'tags', 'type', 'url', 'version', 'versions_url', 'weekly_downloads', ) writeable_fields = ( 'categories', 'description', 'developer_comments', 'homepage', 'is_disabled', 'is_experimental', 'name', 'requires_payment', 'slug', 'summary', 'support_email', 'support_url', 'tags', 'version', ) read_only_fields = tuple(set(fields) - set(writeable_fields)) def __init__(self, instance=None, data=serializers.empty, **kwargs): if instance and isinstance(data, dict): data.pop('version', None) # we only support version field for create super().__init__(instance=instance, data=data, **kwargs) def to_representation(self, obj): data = super().to_representation(obj) request = self.context.get('request', None) if request and is_gate_active(request, 'del-addons-created-field'): data.pop('created', None) if request and not is_gate_active(request, 'is-source-public-shim'): data.pop('is_source_public', None) if request and not is_gate_active(request, 'is-featured-addon-shim'): data.pop('is_featured', None) return data def get_has_eula(self, obj): return bool(getattr(obj, 'has_eula', obj.eula)) def get_is_featured(self, obj): # featured is gone, but we need to keep the API backwards compatible so # fake it with promoted status instead. return bool(obj.promoted and obj.promoted.group == RECOMMENDED) def get_has_privacy_policy(self, obj): return bool(getattr(obj, 'has_privacy_policy', obj.privacy_policy)) def get_url(self, obj): # Use absolutify(get_detail_url()), get_absolute_url() calls # get_url_path() which does an extra check on current_version that is # annoying in subclasses which don't want to load that version. return absolutify(obj.get_detail_url()) def get_edit_url(self, obj): return absolutify(obj.get_dev_url()) def get_ratings_url(self, obj): return absolutify(obj.ratings_url) def get_versions_url(self, obj): return absolutify(obj.versions_url) def get_review_url(self, obj): return absolutify(reverse('reviewers.review', args=[obj.pk])) def get_icon_url(self, obj): return absolutify(obj.get_icon_url(64)) def get_icons(self, obj): get_icon = obj.get_icon_url return { str(size): absolutify(get_icon(size)) for size in amo.ADDON_ICON_SIZES } def get_ratings(self, obj): ratings = { 'average': obj.average_rating, 'bayesian_average': obj.bayesian_rating, 'count': obj.total_ratings, 'text_count': obj.text_ratings_count, } if (request := self.context.get( 'request', None)) and (grouped := get_grouped_ratings( request, obj)):