class FeedItemSerializer(URLSerializerMixin, serializers.ModelSerializer): """ A serializer for the FeedItem class, which wraps all items that live on the feed. """ carrier = SlugChoiceField(required=False, choices_dict=mkt.carriers.CARRIER_MAP) region = SlugChoiceField(required=False, choices_dict=mkt.regions.REGION_LOOKUP) category = SlugModelChoiceField( required=False, queryset=Category.objects.filter(type=amo.ADDON_WEBAPP)) item_type = serializers.SerializerMethodField('get_item_type') # Types of objects that are allowed to be a feed item. app = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedAppSerializer()) brand = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedBrandSerializer()) class Meta: fields = ('app', 'brand', 'carrier', 'category', 'id', 'item_type', 'region', 'url') item_types = ( 'app', 'brand', ) model = FeedItem url_basename = 'feeditems' def validate(self, attrs): """ Ensure that at least one object type is specified. """ item_changed = any(k for k in self.Meta.item_types if k in attrs.keys()) num_defined = sum(1 for item in self.Meta.item_types if attrs.get(item)) if item_changed and num_defined != 1: message = ('A valid value for exactly one of the following ' 'parameters must be defined: %s' % ','.join(self.Meta.item_types)) raise serializers.ValidationError(message) return attrs def get_item_type(self, obj): for item_type in self.Meta.item_types: if getattr(obj, item_type): return item_type return
class WebsiteAbuseSerializer(BaseAbuseSerializer): website = SplitField( serializers.PrimaryKeyRelatedField(queryset=Website.objects), WebsiteSerializer()) class Meta(BaseAbuseSerializer.Meta): fields = BaseAbuseSerializer.Meta.fields + ('website',)
class UserAbuseSerializer(BaseAbuseSerializer): user = SplitField( serializers.PrimaryKeyRelatedField(queryset=UserProfile.objects), UserSerializer()) class Meta(BaseAbuseSerializer.Meta): fields = BaseAbuseSerializer.Meta.fields + ('user',)
class FeedAppSerializer(URLSerializerMixin, serializers.ModelSerializer): app = SplitField(relations.PrimaryKeyRelatedField(required=True), AppSerializer()) description = TranslationSerializerField(required=False) preview = SplitField(relations.PrimaryKeyRelatedField(required=False), PreviewSerializer()) pullquote_attribution = TranslationSerializerField(required=False) pullquote_rating = serializers.IntegerField(required=False) pullquote_text = TranslationSerializerField(required=False) class Meta: fields = ('app', 'description', 'id', 'preview', 'pullquote_attribution', 'pullquote_rating', 'pullquote_text', 'url') model = FeedApp url_basename = 'feedapp'
class AppAbuseSerializer(BaseAbuseSerializer): app = SplitField( SlugOrPrimaryKeyRelatedField(source='addon', slug_field='app_slug', queryset=Webapp.objects.all()), SimpleAppSerializer(source='addon')) class Meta(BaseAbuseSerializer.Meta): fields = BaseAbuseSerializer.Meta.fields + ('app',)
class ExtensionAbuseSerializer(BaseAbuseSerializer): extension = SplitField( SlugOrPrimaryKeyRelatedField( source='extension', slug_field='slug', queryset=Extension.objects.without_deleted().public()), ExtensionSerializer()) class Meta(BaseAbuseSerializer.Meta): fields = BaseAbuseSerializer.Meta.fields + ('extension',)
class AppAbuseSerializer(BaseAbuseSerializer): app = SplitField( SlugOrPrimaryKeyRelatedField(source='addon', slug_field='app_slug', queryset=Webapp.objects.all()), SimpleAppSerializer(source='addon')) class Meta: model = AbuseReport fields = ('text', 'ip_address', 'reporter', 'app')
class BaseAbuseSerializer(serializers.ModelSerializer): text = serializers.CharField(source='message') ip_address = serializers.CharField(required=False) reporter = SplitField(serializers.PrimaryKeyRelatedField(required=False), UserSerializer()) def save(self, force_insert=False): serializers.ModelSerializer.save(self) del self.data['ip_address'] return self.object
class FeedAppSerializer(URLSerializerMixin, serializers.ModelSerializer): """Thin wrappers around apps w/ metadata related to its feature in feed.""" app = SplitField(relations.PrimaryKeyRelatedField(required=True), AppSerializer()) description = TranslationSerializerField(required=False) image = CollectionImageField(source='*', view_name='feed-app-image-detail', format='png') preview = SplitField(relations.PrimaryKeyRelatedField(required=False), PreviewSerializer()) pullquote_attribution = TranslationSerializerField(required=False) pullquote_rating = serializers.IntegerField(required=False) pullquote_text = TranslationSerializerField(required=False) class Meta: fields = ('app', 'background_color', 'description', 'feedapp_type', 'id', 'image', 'preview', 'pullquote_attribution', 'pullquote_rating', 'pullquote_text', 'slug', 'url') model = FeedApp url_basename = 'feedapps'
class FeedAppSerializer(ValidateSlugMixin, URLSerializerMixin, serializers.ModelSerializer): """ A serializer for the FeedApp class, which highlights a single app and some additional metadata (e.g. a review or a screenshot). """ app = SplitField( relations.PrimaryKeyRelatedField(required=True, queryset=Webapp.objects), AppSerializer()) background_image = FeedImageField(allow_null=True) description = TranslationSerializerField(required=False) preview = SplitField( relations.PrimaryKeyRelatedField(required=False, queryset=Preview.objects), FeedPreviewESSerializer()) pullquote_rating = serializers.IntegerField(required=False, max_value=5, min_value=1) pullquote_text = TranslationSerializerField(required=False) class Meta: fields = ('app', 'background_color', 'background_image', 'color', 'created', 'description', 'id', 'preview', 'pullquote_attribution', 'pullquote_rating', 'pullquote_text', 'slug', 'type', 'url') model = FeedApp url_basename = 'feedapps' def validate(self, attrs): """ Require `pullquote_text` if `pullquote_rating` or `pullquote_attribution` are set. """ if (not attrs.get('pullquote_text') and (attrs.get('pullquote_rating') or attrs.get('pullquote_attribution'))): raise ValidationError('Pullquote text required if rating or ' 'attribution is defined.') return attrs
class FeedAppSerializer(URLSerializerMixin, serializers.ModelSerializer): """ A serializer for the FeedApp class, which highlights a single app and some additional metadata (e.g. a review or a screenshot). """ app = SplitField(relations.PrimaryKeyRelatedField(required=True), AppSerializer()) description = TranslationSerializerField(required=False) background_image = CollectionImageField( source='*', view_name='api-v2:feed-app-image-detail', format='png') preview = SplitField(relations.PrimaryKeyRelatedField(required=False), PreviewSerializer()) pullquote_rating = serializers.IntegerField(required=False) pullquote_text = TranslationSerializerField(required=False) class Meta: fields = ('app', 'background_color', 'created', 'description', 'feedapp_type', 'id', 'background_image', 'preview', 'pullquote_attribution', 'pullquote_rating', 'pullquote_text', 'slug', 'url') model = FeedApp url_basename = 'feedapps'
class BaseAbuseSerializer(PotatoCaptchaSerializer, serializers.ModelSerializer): text = serializers.CharField(source='message') reporter = SplitField(serializers.PrimaryKeyRelatedField(required=False), UserSerializer()) class Meta: model = AbuseReport fields = ('text', 'reporter') def validate(self, attrs): request = self.context['request'] if request.user.is_authenticated(): attrs['reporter'] = request.user else: attrs['reporter'] = None attrs['ip_address'] = request.META.get('REMOTE_ADDR', '') return super(BaseAbuseSerializer, self).validate(attrs)
class FeedItemSerializer(URLSerializerMixin, serializers.ModelSerializer): """ A serializer for the FeedItem class, which wraps all items that live on the feed. """ carrier = SlugChoiceField(required=False, choices_dict=mkt.carriers.CARRIER_MAP) region = SlugChoiceField(required=False, choices_dict=mkt.regions.REGION_LOOKUP) category = UnicodeChoiceField(required=False, choices=CATEGORY_CHOICES) item_type = serializers.SerializerMethodField('get_item_type') # Types of objects that are allowed to be a feed item. app = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedAppSerializer()) brand = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedBrandSerializer()) collection = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedCollectionSerializer()) shelf = SplitField(relations.PrimaryKeyRelatedField(required=False), FeedShelfSerializer()) class Meta: fields = ('app', 'brand', 'carrier', 'category', 'collection', 'id', 'item_type', 'region', 'shelf', 'url') item_types = ('app', 'brand', 'collection', 'shelf',) model = FeedItem url_basename = 'feeditems' def validate(self, attrs): """ Ensure that at least one object type is specified. """ item_changed = any(k for k in self.Meta.item_types if k in attrs.keys()) num_defined = sum(1 for item in self.Meta.item_types if attrs.get(item)) if item_changed and num_defined != 1: message = ('A valid value for exactly one of the following ' 'parameters must be defined: %s' % ','.join( self.Meta.item_types)) raise serializers.ValidationError(message) return attrs def get_item_type(self, obj): for item_type in self.Meta.item_types: if getattr(obj, item_type): return item_type return def validate_shelf(self, attrs, source): """ If `shelf` is defined, validate that the FeedItem's `carrier` and `region` match the `carrier` and `region on `shelf`. """ shelf_id = attrs.get(source) if shelf_id: shelf = FeedShelf.objects.get(pk=shelf_id) carrier = CARRIER_CHOICE_DICT[shelf.carrier] if attrs.get('carrier') != carrier.slug: raise serializers.ValidationError( 'Feed item carrier does not match operator shelf carrier.') region = REGIONS_CHOICES_ID_DICT[shelf.region] if attrs.get('region') != region.slug: raise serializers.ValidationError( 'Feed item region does not match operator shelf region.') return attrs
class UserAbuseSerializer(BaseAbuseSerializer): user = SplitField(serializers.PrimaryKeyRelatedField(), UserSerializer()) class Meta(BaseAbuseSerializer.Meta): fields = BaseAbuseSerializer.Meta.fields + ('user',)
class UserAbuseSerializer(BaseAbuseSerializer): user = SplitField(serializers.PrimaryKeyRelatedField(), UserSerializer()) class Meta: model = AbuseReport fields = ('text', 'ip_address', 'reporter', 'user')
class PotatoSerializer(Serializer): spud = SplitField(CharField(), SpudSerializer())
class RatingSerializer(serializers.ModelSerializer): app = SplitField( SlugOrPrimaryKeyRelatedField(slug_field='app_slug', queryset=Webapp.objects.all(), source='addon'), serializers.HyperlinkedRelatedField(view_name='app-detail', read_only=True, source='addon')) body = serializers.CharField() user = UserSerializer(read_only=True) report_spam = serializers.SerializerMethodField('get_report_spam_link') resource_uri = serializers.HyperlinkedIdentityField( view_name='ratings-detail') is_author = serializers.SerializerMethodField('get_is_author') has_flagged = serializers.SerializerMethodField('get_has_flagged') version = SimpleVersionSerializer(read_only=True) lang = serializers.SerializerMethodField('get_lang') class Meta: model = Review fields = ('app', 'body', 'created', 'has_flagged', 'is_author', 'lang', 'modified', 'rating', 'report_spam', 'resource_uri', 'user', 'version') def __init__(self, *args, **kwargs): super(RatingSerializer, self).__init__(*args, **kwargs) if 'request' in self.context: self.request = self.context['request'] else: self.request = None if 'view' in self.context and hasattr(self.context['view'], 'app'): self.app = self.context['view'].app if not self.request or not self.request.user.is_authenticated(): self.fields.pop('is_author') self.fields.pop('has_flagged') if self.request and self.request.method in ('PUT', 'PATCH'): # Don't let users modify 'app' field at edit time self.fields['app'].read_only = True def to_native(self, obj): # When we have an `app` set on the serializer, we know it's because the # view was filtering on this app, so we can safely overwrite the # `addon` property on the instance with it, saving some costly queries. app = getattr(self, 'app', None) if app is not None: obj.addon = app return super(RatingSerializer, self).to_native(obj) def get_report_spam_link(self, obj): return reverse('ratings-flag', kwargs={'pk': obj.pk}) def get_is_author(self, obj): return obj.user.pk == self.request.user.pk def get_has_flagged(self, obj): return (not self.get_is_author(obj) and obj.reviewflag_set.filter(user=self.request.user).exists()) def get_lang(self, obj): if obj.pk is None: return self.request.LANG else: return obj.lang def validate(self, attrs): if not getattr(self, 'object'): # If we are creating a rating, then we need to do various checks on # the app. Because these checks need the version as well, we have # to do them here and not in validate_app(). # Assign user and ip_address. It won't change once the review is # created. user = self.request.user attrs['user'] = user attrs['ip_address'] = self.request.META.get('REMOTE_ADDR', '') guessed_lang = guess_language(attrs['body']) if guessed_lang is None: attrs['lang'] = user.lang else: attrs['lang'] = guessed_lang # If the app is packaged, add in the current version. if attrs['addon'].is_packaged: attrs['version'] = attrs['addon'].current_version # Return 409 if the user has already reviewed this app. app = attrs['addon'] qs = self.context['view'].queryset.filter(addon=app, user=user) if app.is_packaged: qs = qs.filter(version=attrs['version']) if qs.exists(): raise Conflict('You have already reviewed this app.') # Return 403 is the app is not public. if not app.is_public(): raise PermissionDenied('The app requested is not public.') # Return 403 if the user is attempting to review their own app. if app.has_author(user): raise PermissionDenied('You may not review your own app.') # Return 403 if not a free app and the user hasn't purchased it. if app.is_premium() and not app.is_purchased(user): raise PermissionDenied("You may not review paid apps you " "haven't purchased.") # Return 403 if the app is not available in the current region. current_region = get_region() if not app.listed_in(region=current_region): raise PermissionDenied('App not available in region "%s".' % current_region.slug) return attrs def validate_app(self, attrs, source): # Don't allow users to change the app on an existing rating. if getattr(self, 'object'): attrs[source] = self.object.addon return attrs def validate_rating(self, attrs, source): # Don't allow user to submit rating outside the range valid_ratings = [1, 2, 3, 4, 5] # ensure rating key is present if source not in attrs: raise serializers.ValidationError("Rating key is required") value = attrs[source] rating = int(value) if value else value # ensure rating is in desired range if rating not in valid_ratings: raise serializers.ValidationError("Rating must be between 1-5") return attrs
class RatingSerializer(serializers.ModelSerializer): app = SplitField( SlugOrPrimaryKeyRelatedField(slug_field='app_slug', queryset=Webapp.objects.all(), source='addon'), serializers.HyperlinkedRelatedField(view_name='app-detail', read_only=True, source='addon')) body = serializers.CharField() user = AccountSerializer(read_only=True) report_spam = serializers.SerializerMethodField('get_report_spam_link') resource_uri = serializers.HyperlinkedIdentityField( view_name='ratings-detail') is_author = serializers.SerializerMethodField('get_is_author') has_flagged = serializers.SerializerMethodField('get_has_flagged') version = SimpleVersionSerializer(read_only=True) class Meta: model = Review fields = ('app', 'body', 'created', 'has_flagged', 'is_author', 'modified', 'rating', 'report_spam', 'resource_uri', 'user', 'version') def __init__(self, *args, **kwargs): super(RatingSerializer, self).__init__(*args, **kwargs) if 'request' in self.context: self.request = self.context['request'] else: self.request = None if not self.request or not self.request.amo_user: self.fields.pop('is_author') self.fields.pop('has_flagged') if self.request and self.request.method in ('PUT', 'PATCH'): # Don't let users modify 'app' field at edit time self.fields['app'].read_only = True def get_report_spam_link(self, obj): return reverse('ratings-flag', kwargs={'pk': obj.pk}) def get_is_author(self, obj): return obj.user.pk == self.request.amo_user.pk def get_has_flagged(self, obj): return (not self.get_is_author(obj) and obj.reviewflag_set.filter(user=self.request.amo_user).exists()) def validate(self, attrs): if not getattr(self, 'object'): # If we are creating a rating, then we need to do various checks on # the app. Because these checks need the version as well, we have # to do them here and not in validate_app(). # Assign user and ip_address. It won't change once the review is # created. attrs['user'] = self.request.amo_user attrs['ip_address'] = self.request.META.get('REMOTE_ADDR', '') # If the app is packaged, add in the current version. if attrs['addon'].is_packaged: attrs['version'] = attrs['addon'].current_version # Return 409 if the user has already reviewed this app. app = attrs['addon'] amo_user = self.request.amo_user qs = self.context['view'].queryset.filter(addon=app, user=amo_user) if app.is_packaged: qs = qs.filter(version=attrs['version']) if qs.exists(): raise Conflict('You have already reviewed this app.') # Return 403 is the app is not public. if not app.is_public(): raise PermissionDenied('The app requested is not public.') # Return 403 if the user is attempting to review their own app. if app.has_author(amo_user): raise PermissionDenied('You may not review your own app.') # Return 403 if not a free app and the user hasn't purchased it. if app.is_premium() and not app.is_purchased(amo_user): raise PermissionDenied("You may not review paid apps you " "haven't purchased.") # Return 403 if the app is not available in the current region. current_region = get_region() if not app.listed_in(region=current_region): raise PermissionDenied('App not available in region "%s".' % current_region.slug) return attrs def validate_app(self, attrs, source): # Don't allow users to change the app on an existing rating. if getattr(self, 'object'): attrs[source] = self.object.addon return attrs
class RatingSerializer(serializers.ModelSerializer): app = SplitField( SlugOrPrimaryKeyRelatedField(slug_field='app_slug', queryset=Webapp.objects.all(), source='addon'), serializers.HyperlinkedRelatedField(view_name='app-detail', read_only=True, source='addon')) body = serializers.CharField() user = AccountSerializer(read_only=True) report_spam = serializers.SerializerMethodField('get_report_spam_link') resource_uri = serializers.HyperlinkedIdentityField( view_name='ratings-detail') is_author = serializers.SerializerMethodField('get_is_author') has_flagged = serializers.SerializerMethodField('get_has_flagged') version = SimpleVersionSerializer(read_only=True) class Meta: model = Review fields = ('app', 'body', 'created', 'has_flagged', 'is_author', 'modified', 'rating', 'report_spam', 'resource_uri', 'user', 'version') def __init__(self, *args, **kwargs): super(RatingSerializer, self).__init__(*args, **kwargs) if 'request' in self.context: self.request = self.context['request'] else: self.request = None if not self.request or not self.request.amo_user: self.fields.pop('is_author') self.fields.pop('has_flagged') if self.request.method in ('PUT', 'PATCH'): # Don't let users modify 'app' field at edit time self.fields['app'].read_only = True def get_report_spam_link(self, obj): return reverse('ratings-flag', kwargs={'pk': obj.pk}) def get_is_author(self, obj): return obj.user.pk == self.request.amo_user.pk def get_has_flagged(self, obj): return (not self.get_is_author(obj) and obj.reviewflag_set.filter(user=self.request.amo_user).exists()) @classmethod def get_app_from_value(cls, value): try: app = Webapp.objects.valid().get(id=value) except (Webapp.DoesNotExist, ValueError): try: app = Webapp.objects.valid().get(app_slug=value) except Webapp.DoesNotExist: raise serializers.ValidationError('Invalid app') if not app.listed_in(region=REGIONS_DICT[get_region()]): raise serializers.ValidationError( 'App not available in this region') return app def validate(self, attrs): attrs['user'] = self.request.amo_user attrs['ip_address'] = self.request.META.get('REMOTE_ADDR', '') if not getattr(self, 'object'): if attrs['addon'].is_packaged: attrs['version'] = attrs['addon'].current_version # Return 409 if the user has already reviewed this app. app = attrs['addon'] amo_user = self.request.amo_user qs = self.context['view'].queryset.filter(addon=app, user=amo_user) if app.is_packaged: qs = qs.filter(version=attrs['version']) if qs.exists(): raise Conflict('You have already reviewed this app.') # Return 403 if the user is attempting to review their own app: if app.has_author(amo_user): raise PermissionDenied('You may not review your own app.') # Return 403 if not a free app and the user hasn't purchased it. if app.is_premium() and not app.is_purchased(amo_user): raise PermissionDenied("You may not review paid apps you " "haven't purchased.") return attrs def validate_app(self, attrs, source): if not getattr(self, 'object'): app = attrs[source] attrs[source] = RatingSerializer.get_app_from_value(app.pk) else: attrs[source] = self.object.addon return attrs