def test_validate_non_list():
    """
    When a ListField is given a non-list value, then validate should raise a ValidationError.
    """
    field = ListField()
    with pytest.raises(ValidationError):
        field.validate('notAList')
def test_to_native_no_item_field():
    """
    When a ListField has no item-field, to_native should return the data it was given un-processed.
    """
    field = ListField()
    obj = list(range(5))
    data = field.to_native(obj)
    assert data == obj
def test_missing_required_list():
    """
    When a ListField requires a value, then validate should raise a ValidationError on a missing
    (None) value.
    """
    field = ListField()
    with pytest.raises(ValidationError):
        field.validate(None)
def test_validate_empty_list():
    """
    When a ListField requires a value, then validate should raise a ValidationError on an empty
    value.
    """
    field = ListField()
    with pytest.raises(ValidationError):
        field.validate([])
def test_validate_elements_invalid():
    """
    When a ListField is given a list containing elements that are invalid for the item-field, then
    validate should raise a ValidationError.
    """
    field = ListField(CharField(max_length=5))
    with pytest.raises(ValidationError):
        field.validate(["012345", "012345"])
def test_to_internal_value_with_item_field():
    """
    When a ListField has an item-field, to_internal_value should return a list of elements resulting from
    the application of the item-field's to_internal_value method to each element of the input data list.
    """
    field = ListField(child=DateField())
    data = ["2000-01-01", "2000-01-02"]
    obj = field.to_internal_value(data)
    assert [date(2000, 1, 1), date(2000, 1, 2)] == obj
예제 #7
0
 def test_to_native_no_item_field(self):
     """
     When a ListField has no item-field, to_native should return the data it was given
     un-processed.
     """
     field = ListField()
     obj = range(5)
     data = field.to_native(obj)
     self.assertEqual(obj, data)
예제 #8
0
 def test_from_native_no_item_field(self):
     """
     When a ListField has no item-field, from_native should return the data it was given
     un-processed.
     """
     field = ListField()
     data = range(5)
     obj = field.from_native(data)
     self.assertEqual(data, obj)
def test_from_native_no_item_field():
    """
    When a ListField has no item-field, from_native should return the data it was given
    un-processed.
    """
    field = ListField()
    data = list(range(5))
    obj = field.from_native(data)
    assert data == obj
def test_from_native_with_item_field():
    """
    When a ListField has an item-field, from_native should return a list of elements resulting from
    the application of the item-field's from_native method to each element of the input data list.
    """
    field = ListField(DateField())
    data = ["2000-01-01", "2000-01-02"]
    obj = field.from_native(data)
    assert [date(2000, 1, 1), date(2000, 1, 2)] == obj
def test_to_native_with_item_field():
    """
    When a ListField has an item-field, to_native should return a list of elements resulting from
    the application of the item-field's to_native method to each element of the input object list.
    """
    field = ListField(DateField(format=ISO_8601))
    obj = [date(2000, 1, 1), date(2000, 1, 2)]
    data = field.to_native(obj)
    assert ["2000-01-01", "2000-01-02"] == data
예제 #12
0
def test_validate_not_required_non_list():
    """
    When a ListField is given a null value and is not required, do not raise a ValidationError.
    """
    field = ListField(required=False)

    try:
        field.validate(None)
    except ValidationError as e:
        assert False, "ValidationError was raised"
예제 #13
0
 def test_validate_elements_valid(self):
     """
     When a ListField is given a list whose elements are valid for the item-field, then validate
     will not raise a ValidationError.
     """
     field = ListField(CharField(max_length=5))
     try:
         field.validate(["a", "b", "c"])
     except ValidationError:
         self.fail("ValidationError was raised")
def test_validate_elements_valid():
    """
    When a ListField is given a list whose elements are valid for the item-field, then validate
    should not raise a ValidationError.
    """
    field = ListField(CharField(max_length=5))
    try:
        field.validate(["a", "b", "c"])
    except ValidationError:
        assert False, "ValidationError was raised"
def test_errors_non_list():
    """
    When a ListField is given a non-list value, then there should be one error related to the type
    mismatch.
    """
    field = ListField()
    try:
        field.validate('notAList')
        assert False, 'Expected ValidationError'
    except ValidationError as e:
        assert 'notAList is not a list', e.messages[0]
def test_errors_non_list():
    """
    When a ListField is given a non-list value, then there should be one error related to the type
    mismatch.
    """
    field = ListField(child=DateField())
    try:
        field.to_internal_value('notAList')
        assert False, 'Expected ValidationError'
    except ValidationError as e:
        pass
예제 #17
0
class RouteSerializer(serializers.ModelSerializer):
    user_id = serializers.IntegerField(required=False)
    form_id = serializers.IntegerField(required=False)
    dests = ListField(serializers.IntegerField())

    class Meta:
        fields = (
            'id',
            'created_at',
            'updated_at',
            'form',
            'form_id',
            'user',
            'user_id',
            'group',
            'group_id',
            'dests'
        )
        model = Route
예제 #18
0
class ExtensionSerializer(ModelSerializer):
    description = TranslationSerializerField(read_only=True)
    device_types = ListField(CharField(), source='device_names')
    icons = SerializerMethodField('get_icons')
    latest_public_version = ExtensionVersionSerializer(
        source='latest_public_version', read_only=True)
    latest_version = ExtensionVersionSerializer(source='latest_version',
                                                read_only=True)
    mini_manifest_url = CharField(source='mini_manifest_url', read_only=True)
    name = TranslationSerializerField(read_only=True)
    status = ReverseChoiceField(choices_dict=STATUS_CHOICES_API_v2,
                                read_only=True)

    # FIXME: latest_version potentially expose private data.
    # Nothing extremely major, but maybe we care. Not a fan of moving it to
    # another endpoint since that'd mean developers and reviewers would need
    # to use that other endpoint instead of the regular one, but maybe that's
    # the way to go ? That endpoint could include all versions info, too.

    def get_icons(self, obj):
        return {size: obj.get_icon_url(size) for size in (64, 128)}

    class Meta:
        model = Extension
        fields = [
            'id',
            'author',
            'description',
            'device_types',
            'disabled',
            'icons',
            'last_updated',
            'latest_version',
            'latest_public_version',
            'mini_manifest_url',
            'name',
            'slug',
            'status',
            'uuid',
        ]
예제 #19
0
class ListSerializer(serializers.Serializer):
    emails = ListField(child=serializers.EmailField(), required=False)
예제 #20
0
class SchoolSerializer(serializers.ModelSerializer):
    registered = serializers.DateTimeField(format='iso-8601', required=False)
    fees_owed = DecimalField(read_only=True)
    fees_paid = DecimalField(read_only=True)
    country_preferences = ListField(serializers.IntegerField(),
                                    source='country_preference_ids')

    class Meta:
        model = School
        fields = (
            'id',
            'registered',
            'name',
            'address',
            'city',
            'state',
            'zip_code',
            'country',
            'primary_name',
            'primary_gender',
            'primary_email',
            'primary_phone',
            'primary_type',
            'secondary_name',
            'secondary_gender',
            'secondary_email',
            'secondary_phone',
            'secondary_type',
            'program_type',
            'times_attended',
            'international',
            'waitlist',
            'beginner_delegates',
            'intermediate_delegates',
            'advanced_delegates',
            'spanish_speaking_delegates',
            'country_preferences',
            'committeepreferences',
            'registration_comments',
            'fees_owed',
            'fees_paid',
        )

    def validate_name(self, attrs, source):
        school_name = attrs[source]

        if School.objects.filter(name=school_name).exists():
            raise serializers.ValidationError(
                'A school with the name "%s" has already been registered.' %
                school_name)

        validators.name(school_name)

        return attrs

    def validate_state(self, attrs, source):
        school_state = attrs[source]

        validators.name(school_state)

        return attrs

    def validate_country(self, attrs, source):
        school_country = attrs[source]

        validators.name(school_country)

        return attrs

    def validate_primary_phone(self, attrs, source):
        international = attrs['international']
        number = attrs[source]

        if international:
            validators.phone_international(number)
        else:
            validators.phone_domestic(number)

        return attrs

    def validate_address(self, attrs, source):
        school_address = attrs[source]

        validators.address(school_address)

        return attrs

    def validate_city(self, attrs, source):
        school_city = attrs[source]

        validators.name(school_city)

        return attrs

    def validate_zip(self, attrs, source):
        school_zip = attrs[source]

        validators.numeric(school_zip)

        return attrs

    def validate_primary_name(self, attrs, source):
        primary_name = attrs[source]

        validators.name(primary_name)

        return attrs

    def validate_primary_email(self, attrs, source):
        primary_email = attrs[source]

        validators.email(primary_email)

        return attrs

    def validate_secondary_name(self, attrs, source):
        secondary_name = attrs.get(source)

        if secondary_name:
            validators.name(secondary_name)

        return attrs

    def validate_secondary_email(self, attrs, source):
        secondary_email = attrs.get(source)

        if secondary_email:
            validators.email(secondary_email)

        return attrs

    def validate_secondary_phone(self, attrs, source):
        number = attrs.get(source)
        international = attrs['international']

        if number:
            if international:
                validators.phone_international(number)
            else:
                validators.phone_domestic(number)

        return attrs
예제 #21
0
 def test_validate_non_list(self):
     """
     When a ListField is given a non-list value, then validate will raise a ValidationError.
     """
     field = ListField()
     self.assertRaises(ValidationError, field.validate, 'notAList')
예제 #22
0
class ContainerListSerializer(serializers.Serializer):
    embedded = ListField(child=EmbeddedSerializer())
예제 #23
0
class AppSerializer(serializers.ModelSerializer):
    app_type = serializers.ChoiceField(
        choices=mkt.ADDON_WEBAPP_TYPES_LOOKUP.items(), read_only=True)
    author = serializers.CharField(source='developer_name', read_only=True)
    categories = ListField(serializers.ChoiceField(choices=CATEGORY_CHOICES),
                           required=True)
    content_ratings = serializers.SerializerMethodField('get_content_ratings')
    created = serializers.DateField(read_only=True)
    current_version = serializers.CharField(source='current_version.version',
                                            read_only=True)
    default_locale = serializers.CharField(read_only=True)
    device_types = SemiSerializerMethodField('get_device_types')
    description = TranslationSerializerField(required=False)
    homepage = TranslationSerializerField(required=False)
    feature_compatibility = serializers.SerializerMethodField(
        'get_feature_compatibility')
    file_size = serializers.IntegerField(source='file_size', read_only=True)
    icons = serializers.SerializerMethodField('get_icons')
    id = serializers.IntegerField(source='pk', required=False)
    is_disabled = serializers.BooleanField(read_only=True, default=False)
    is_homescreen = serializers.SerializerMethodField('get_is_homescreen')
    is_offline = serializers.BooleanField(read_only=True)
    is_packaged = serializers.BooleanField(read_only=True)
    last_updated = serializers.DateField(read_only=True)
    manifest_url = serializers.CharField(source='get_manifest_url',
                                         read_only=True)
    modified = serializers.DateField(read_only=True)
    name = TranslationSerializerField(required=False)
    package_path = serializers.CharField(source='get_package_path',
                                         read_only=True)
    payment_account = serializers.SerializerMethodField('get_payment_account')
    payment_required = serializers.SerializerMethodField(
        'get_payment_required')
    premium_type = ReverseChoiceField(choices_dict=mkt.ADDON_PREMIUM_API,
                                      required=False)
    previews = PreviewSerializer(many=True,
                                 required=False,
                                 source='all_previews')
    price = SemiSerializerMethodField('get_price')
    price_locale = serializers.SerializerMethodField('get_price_locale')
    privacy_policy = LargeTextField(view_name='app-privacy-policy-detail',
                                    required=False)
    promo_imgs = serializers.SerializerMethodField('get_promo_imgs')
    public_stats = serializers.BooleanField(read_only=True)
    ratings = serializers.SerializerMethodField('get_ratings_aggregates')
    regions = RegionSerializer(read_only=True, source='get_regions', many=True)
    release_notes = TranslationSerializerField(
        read_only=True, source='current_version.releasenotes')
    resource_uri = serializers.HyperlinkedIdentityField(view_name='app-detail')
    slug = serializers.CharField(source='app_slug', required=False)
    status = serializers.IntegerField(read_only=True)
    support_email = TranslationSerializerField(required=False)
    support_url = TranslationSerializerField(required=False)
    supported_locales = serializers.SerializerMethodField(
        'get_supported_locales')
    tags = serializers.SerializerMethodField('get_tags')
    upsell = serializers.SerializerMethodField('get_upsell')
    upsold = serializers.HyperlinkedRelatedField(view_name='app-detail',
                                                 source='upsold.free',
                                                 required=False,
                                                 queryset=Webapp.objects.all())
    user = serializers.SerializerMethodField('get_user_info')
    versions = serializers.SerializerMethodField('get_versions')

    class Meta:
        model = Webapp
        fields = [
            'app_type', 'author', 'categories', 'content_ratings', 'created',
            'current_version', 'default_locale', 'description', 'device_types',
            'feature_compatibility', 'file_size', 'homepage', 'hosted_url',
            'icons', 'id', 'is_disabled', 'is_homescreen', 'is_offline',
            'is_packaged', 'last_updated', 'manifest_url', 'name',
            'package_path', 'payment_account', 'payment_required',
            'premium_type', 'previews', 'price', 'price_locale',
            'privacy_policy', 'promo_imgs', 'public_stats', 'release_notes',
            'ratings', 'regions', 'resource_uri', 'slug', 'status',
            'support_email', 'support_url', 'supported_locales', 'tags',
            'upsell', 'upsold', 'user', 'versions'
        ]

    def _get_region_id(self):
        request = self.context.get('request')
        REGION = getattr(request, 'REGION', None)
        return REGION.id if REGION else None

    def _get_region_slug(self):
        request = self.context.get('request')
        REGION = getattr(request, 'REGION', None)
        return REGION.slug if REGION else None

    def get_content_ratings(self, app):
        body = mkt.regions.REGION_TO_RATINGS_BODY().get(
            self._get_region_slug(), 'generic')

        return {
            'body':
            body,
            'rating':
            app.get_content_ratings_by_body().get(body, None),
            'descriptors': (app.rating_descriptors.to_keys_by_body(body)
                            if hasattr(app, 'rating_descriptors') else []),
            'descriptors_text': ([
                mkt.iarc_mappings.REVERSE_DESCS[key]
                for key in app.rating_descriptors.to_keys_by_body(body)
            ] if hasattr(app, 'rating_descriptors') else []),
            'interactives': (app.rating_interactives.to_keys() if hasattr(
                app, 'rating_interactives') else []),
            'interactives_text': ([
                mkt.iarc_mappings.REVERSE_INTERACTIVES[key]
                for key in app.rating_interactives.to_keys()
            ] if hasattr(app, 'rating_interactives') else []),
        }

    def get_icons(self, app):
        return dict([(icon_size, app.get_icon_url(icon_size))
                     for icon_size in mkt.CONTENT_ICON_SIZES])

    def get_feature_compatibility(self, app):
        request = self.context['request']
        if not hasattr(request, 'feature_profile'):
            load_feature_profile(request)
        if request.feature_profile is None:
            # No profile information sent, we can't return compatibility,
            # return null.
            return None
        app_features = app.current_version.features.to_list()
        return request.feature_profile.has_features(app_features)

    def get_payment_account(self, app):
        # Avoid a query for payment_account if the app is not premium.
        if not app.is_premium():
            return None

        try:
            # This is a soon to be deprecated API property that only
            # returns the Bango account for historic compatibility.
            app_acct = app.payment_account(PROVIDER_BANGO)
            return reverse('payment-account-detail',
                           args=[app_acct.payment_account.pk])
        except app.PayAccountDoesNotExist:
            return None

    def get_payment_required(self, app):
        if app.has_premium():
            tier = app.get_tier()
            return bool(tier and tier.price)
        return False

    def get_price(self, app):
        if app.has_premium():
            return app.get_price(region=self._get_region_id())
        return None

    def get_price_locale(self, app):
        if app.has_premium():
            return app.get_price_locale(region=self._get_region_id())
        return None

    def get_promo_imgs(self, obj):
        return dict([(promo_img_size, obj.get_promo_img_url(promo_img_size))
                     for promo_img_size in mkt.PROMO_IMG_SIZES])

    def get_ratings_aggregates(self, app):
        return {'average': app.average_rating, 'count': app.total_reviews}

    def get_supported_locales(self, app):
        locs = getattr(app.current_version, 'supported_locales', '')
        if locs:
            return locs.split(',') if isinstance(locs, basestring) else locs
        else:
            return []

    def get_tags(self, app):
        if not hasattr(app, 'tags_list'):
            attach_tags([app])
        return getattr(app, 'tags_list', [])

    def get_upsell(self, app):
        upsell = False
        if app.upsell:
            upsell = app.upsell.premium
        # Only return the upsell app if it's public and we are not in an
        # excluded region.
        if (upsell and upsell.is_public() and self._get_region_id()
                not in upsell.get_excluded_region_ids()):
            return {
                'id': upsell.id,
                'app_slug': upsell.app_slug,
                'icon_url': upsell.get_icon_url(128),
                'name': unicode(upsell.name),
                'resource_uri': reverse('app-detail', kwargs={'pk': upsell.pk})
            }
        else:
            return False

    def get_user_info(self, app):
        request = self.context.get('request')
        if request and request.user.is_authenticated():
            user = request.user
            return {
                'developed':
                app.addonuser_set.filter(user=user,
                                         role=mkt.AUTHOR_ROLE_OWNER).exists(),
                'installed':
                app.has_installed(user),
                'purchased':
                app.pk in user.purchase_ids(),
            }

    def get_is_homescreen(self, app):
        return app.is_homescreen()

    def get_versions(self, app):
        # Disable transforms, we only need two fields: version and pk.
        # Unfortunately, cache-machine gets in the way so we can't use .only()
        # (.no_transforms() is ignored, defeating the purpose), and we can't
        # use .values() / .values_list() because those aren't cached :(
        return dict((v.version, reverse('version-detail', kwargs={'pk': v.pk}))
                    for v in app.versions.all().no_transforms())

    def validate_categories(self, attrs, source):
        if not attrs.get('categories'):
            raise serializers.ValidationError('This field is required.')
        set_categories = set(attrs[source])
        total = len(set_categories)
        max_cat = mkt.MAX_CATEGORIES

        if total > max_cat:
            # L10n: {0} is the number of categories.
            raise serializers.ValidationError(
                ngettext('You can have only {0} category.',
                         'You can have only {0} categories.',
                         max_cat).format(max_cat))

        return attrs

    def get_device_types(self, app):
        with no_translation():
            return [n.api_name for n in app.device_types]

    def save_device_types(self, obj, new_types):
        new_types = [mkt.DEVICE_LOOKUP[d].id for d in new_types]
        old_types = [x.id for x in obj.device_types]

        added_devices = set(new_types) - set(old_types)
        removed_devices = set(old_types) - set(new_types)

        for d in added_devices:
            obj.addondevicetype_set.create(device_type=d)
        for d in removed_devices:
            obj.addondevicetype_set.filter(device_type=d).delete()

        # Send app to re-review queue if public and new devices are added.
        if added_devices and obj.status in mkt.WEBAPPS_APPROVED_STATUSES:
            mark_for_rereview(obj, added_devices, removed_devices)

    def save_upsold(self, obj, upsold):
        current_upsell = obj.upsold
        if upsold and upsold != obj.upsold.free:
            if not current_upsell:
                log.debug('[1@%s] Creating app upsell' % obj.pk)
                current_upsell = AddonUpsell(premium=obj)
            current_upsell.free = upsold
            current_upsell.save()

        elif current_upsell:
            # We're deleting the upsell.
            log.debug('[1@%s] Deleting the app upsell' % obj.pk)
            current_upsell.delete()

    def save_price(self, obj, price):
        premium = obj.premium
        if not premium:
            premium = AddonPremium()
            premium.addon = obj
        premium.price = Price.objects.active().get(price=price)
        premium.save()

    def validate_device_types(self, attrs, source):
        if attrs.get('device_types') is None:
            raise serializers.ValidationError('This field is required.')
        for v in attrs['device_types']:
            if v not in mkt.DEVICE_LOOKUP.keys():
                raise serializers.ValidationError(
                    str(v) + ' is not one of the available choices.')
        return attrs

    def validate_price(self, attrs, source):
        if attrs.get('premium_type',
                     None) not in (mkt.ADDON_FREE, mkt.ADDON_FREE_INAPP):
            valid_prices = Price.objects.exclude(price='0.00').values_list(
                'price', flat=True)
            price = attrs.get('price')
            if not (price and Decimal(price) in valid_prices):
                raise serializers.ValidationError(
                    'Premium app specified without a valid price. Price can be'
                    ' one of %s.' % (', '.join('"%s"' % str(p)
                                               for p in valid_prices), ))
        return attrs

    def restore_object(self, attrs, instance=None):
        # restore_object creates or updates a model instance, during
        # input validation.
        extras = []
        # Upsell bits are handled here because we need to remove it
        # from the attrs dict before deserializing.
        upsold = attrs.pop('upsold.free', None)
        if upsold is not None:
            extras.append((self.save_upsold, upsold))
        price = attrs.pop('price', None)
        if price is not None:
            extras.append((self.save_price, price))
        device_types = attrs['device_types']
        if device_types:
            extras.append((self.save_device_types, device_types))
            del attrs['device_types']
        instance = super(AppSerializer, self).restore_object(attrs,
                                                             instance=instance)
        for f, v in extras:
            f(instance, v)
        return instance
예제 #24
0
class FeedbackSerializer(serializers.Serializer):
    device_id = serializers.CharField(max_length=200)
    messages_id = ListField(serializers.IntegerField())