Beispiel #1
0
 def dispatch(self, request_type, request, **kwargs):
     # Using `Webapp.objects.all()` here forces a new queryset, which for
     # now avoids bug 854505. We're also using this to filter by flagged
     # apps.
     self._meta.queryset_base = Webapp.objects.all()
     self._meta.queryset = self._meta.queryset_base.exclude(
         id__in=get_excluded_in(REGIONS_DICT[get_region()].id))
     return super(AppResource, self).dispatch(request_type, request,
                                              **kwargs)
Beispiel #2
0
 def dispatch(self, request_type, request, **kwargs):
     # Using `Webapp.objects.all()` here forces a new queryset, which for
     # now avoids bug 854505. We're also using this to filter by flagged
     # apps.
     self._meta.queryset_base = Webapp.objects.all()
     self._meta.queryset = self._meta.queryset_base.exclude(
         id__in=Webapp.get_excluded_in(REGIONS_DICT[get_region()]))
     return super(AppResource, self).dispatch(request_type, request,
                                              **kwargs)
Beispiel #3
0
def _filter_search(request, qs, query, filters=None, sorting=None,
                   sorting_default='-popularity', region=None):
    """Filter an ES queryset based on a list of filters."""
    # Intersection of the form fields present and the filters we want to apply.
    filters = filters or DEFAULT_FILTERS
    sorting = sorting or DEFAULT_SORTING
    show = filter(query.get, filters)

    if query.get('q'):
        qs = qs.query(should=True, **name_query(query['q'].lower()))
    if 'cat' in show:
        qs = qs.filter(category=query['cat'])
    if 'price' in show:
        if query['price'] == 'paid':
            qs = qs.filter(premium_type__in=amo.ADDON_PREMIUMS)
        elif query['price'] == 'free':
            qs = qs.filter(premium_type__in=amo.ADDON_FREES, price=0)
    if 'device' in show:
        qs = qs.filter(device=forms.DEVICE_CHOICES_IDS[query['device']])
    if 'premium_types' in show:
        if query.get('premium_types'):
            qs = qs.filter(premium_type__in=query.get('premium_types'))
    if 'app_type' in query and query['app_type']:
        qs = qs.filter(app_type=query['app_type'])
    if 'sort' in show:
        sort_by = None
        if query['sort'] in sorting:
            sort_by = sorting[query['sort']]

        # For "Adolescent" regions popularity is global installs + reviews.

        if query['sort'] == 'popularity' and region and not region.adolescent:
            # For "Mature" regions popularity becomes installs + reviews
            # from only that region.
            sort_by = '-popularity_%s' % region.id

        if sort_by:
            qs = qs.order_by(sort_by)
    elif not query.get('q'):

        if (sorting_default == 'popularity' and region and
            not region.adolescent):
            # For "Mature" regions popularity becomes installs + reviews
            # from only that region.
            sorting_default = '-popularity_%s' % region.id

        # Sort by a default if there was no query so results are predictable.
        qs = qs.order_by(sorting_default)

    region = regions.REGIONS_DICT[get_region()]
    # If the region only supports carrier billing for app purchase,
    # don't list apps that require carrier billing to buy.
    if not region.supports_carrier_billing:
        qs = qs.filter(carrier_billing_only=False)
    return qs
Beispiel #4
0
 def get_app(self, ident):
     try:
         app = Webapp.objects.valid().get(id=ident)
     except (Webapp.DoesNotExist, ValueError):
         try:
             app = Webapp.objects.valid().get(app_slug=ident)
         except Webapp.DoesNotExist:
             raise self.non_form_errors([('app', 'Invalid app')])
     if not app.listed_in(region=REGIONS_DICT[get_region()]):
         raise self.non_form_errors([('app', 'Not available in this region')])
     return app
Beispiel #5
0
 def get_app(self, ident):
     try:
         app = Webapp.objects.valid().get(id=ident)
     except (Webapp.DoesNotExist, ValueError):
         try:
             app = Webapp.objects.valid().get(app_slug=ident)
         except Webapp.DoesNotExist:
             raise self.non_form_errors([('app', 'Invalid app')])
     if not app.listed_in(region=REGIONS_DICT[get_region()]):
         raise self.non_form_errors([('app', 'Not available in this region')
                                     ])
     return app
Beispiel #6
0
 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
Beispiel #7
0
 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
Beispiel #8
0
    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
Beispiel #9
0
 def get_app(self, ident):
     try:
         app = Webapp.objects.by_identifier(ident)
     except Webapp.DoesNotExist:
         raise Http404
     current_region = get_region()
     if ((not app.is_public()
          or not app.listed_in(region=current_region))
          and not check_addon_ownership(self.request, app)):
         # App owners and admin can see the app even if it's not public
         # or not available in the current region. Regular users or
         # anonymous users can't.
         raise PermissionDenied('The app requested is not public or not '
             'available in region "%s".' % current_region.slug)
     return app
Beispiel #10
0
 def get_app(self, ident):
     try:
         app = Webapp.objects.by_identifier(ident)
     except Webapp.DoesNotExist:
         raise Http404
     current_region = get_region()
     if ((not app.is_public() or not app.listed_in(region=current_region))
             and not check_addon_ownership(self.request, app)):
         # App owners and admin can see the app even if it's not public
         # or not available in the current region. Regular users or
         # anonymous users can't.
         raise PermissionDenied('The app requested is not public or not '
                                'available in region "%s".' %
                                current_region.slug)
     return app
Beispiel #11
0
def test_get_region_worldwide(local):
    local.region = 'worldwide'
    eq_(get_region(), regions.RESTOFWORLD)
Beispiel #12
0
def test_get_region_empty():
    eq_(get_region(), regions.WORLDWIDE.slug)
    eq_(get_region_id(), regions.WORLDWIDE.id)
Beispiel #13
0
def test_set_region(local):
    local.region = 'us'

    eq_(get_region(), 'us')
    set_region('es')
    eq_(get_region(), 'es')
Beispiel #14
0
def test_get_region_empty():
    eq_(get_region(), regions.RESTOFWORLD)
Beispiel #15
0
def es_app_to_dict(obj, profile=None, request=None):
    """
    Return app data as dict for API where `app` is the elasticsearch result.
    """
    # Circular import.
    from mkt.developers.models import AddonPaymentAccount
    from mkt.webapps.models import Installed, Webapp

    translation_fields = ('banner_message', 'description', 'homepage', 'name',
                          'release_notes', 'support_email', 'support_url')
    lang = None
    if request and request.method == 'GET' and 'lang' in request.GET:
        lang = request.GET.get('lang', '').lower()

    region_slug = None
    region_id = None
    if request and request.method == 'GET' and 'region' in request.GET:
        region_slug = request.GET.get('region', '').lower()
    if region_slug not in REGIONS_DICT:
        region_slug = get_region()
    region_id = REGIONS_DICT[region_slug].id

    src = obj._source
    is_packaged = src.get('app_type') != amo.ADDON_WEBAPP_HOSTED
    # The following doesn't perform a database query, but gives us useful
    # methods like `get_detail_url` and `get_icon_url`. If you use `app` make
    # sure the calls don't query the database.
    app = Webapp(id=obj._id, app_slug=obj.app_slug, is_packaged=is_packaged,
                 type=amo.ADDON_WEBAPP, icon_type='image/png',
                 modified=getattr(obj, 'modified', None))

    attrs = ('created', 'current_version', 'default_locale', 'is_offline',
             'manifest_url', 'reviewed', 'ratings', 'status',
             'weekly_downloads')
    data = dict((a, getattr(obj, a, None)) for a in attrs)

    # Flatten the localized fields from {'lang': ..., 'string': ...}
    # to {lang: string}.
    for field in translation_fields:
        src_field = '%s_translations' % field
        value_field = src.get(src_field)
        src[src_field] = dict((v.get('lang', ''), v.get('string', ''))
                              for v in value_field) if value_field else {}
        data[field] = get_translations(src, src_field, obj.default_locale,
                                       lang)

    # Generate urls for previews and icons before the data.update() call below
    # adds them to the result.
    previews = getattr(obj, 'previews', [])
    for preview in previews:
        if 'image_url' and 'thumbnail_url' in preview:
            # Old-style index, the full URL is already present, nothing to do.
            # TODO: remove this check once we have re-indexed everything.
            continue
        else:
            # New-style index, we need to build the URLs from the data we have.
            p = Preview(id=preview.pop('id'), modified=preview.pop('modified'),
                        filetype=preview['filetype'])
            preview['image_url'] = p.image_url
            preview['thumbnail_url'] = p.thumbnail_url
    icons = getattr(obj, 'icons', [])
    for icon in icons:
        if 'url' in icon:
            # Old-style index, the full URL is already present, nothing to do.
            # TODO: remove this check once we have re-indexed everything.
            continue
        else:
            # New-style index, we need to build the URLs from the data we have.
            icon['url'] = app.get_icon_url(icon['size'])

    data.update({
        'absolute_url': absolutify(app.get_detail_url()),
        'app_type': 'packaged' if is_packaged else 'hosted',
        'author': src.get('author', ''),
        'banner_regions': src.get('banner_regions', []),
        'categories': [c for c in obj.category],
        'content_ratings': filter_content_ratings_by_region({
            'ratings': dehydrate_content_ratings(
                getattr(obj, 'content_ratings', {})),
            'descriptors': dehydrate_descriptors(
                getattr(obj, 'content_descriptors', {})),
            'interactive_elements': dehydrate_interactives(
                getattr(obj, 'interactive_elements', [])),
            'regions': mkt.regions.REGION_TO_RATINGS_BODY()
        }, region=region_slug),
        'device_types': [DEVICE_TYPES[d].api_name for d in src.get('device')],
        'icons': dict((i['size'], i['url']) for i in src.get('icons')),
        'id': long(obj._id),
        'is_packaged': is_packaged,
        'payment_required': False,
        'premium_type': amo.ADDON_PREMIUM_API[src.get('premium_type')],
        'previews': previews,
        'privacy_policy': reverse('app-privacy-policy-detail',
                                  kwargs={'pk': obj._id}),
        'public_stats': obj.has_public_stats,
        'supported_locales': src.get('supported_locales', ''),
        'slug': obj.app_slug,
        'versions': dict((v.get('version'), v.get('resource_uri')) for v in
                         src.get('versions')),
    })

    if not data['public_stats']:
        data['weekly_downloads'] = None

    def serialize_region(o):
        d = {}
        for field in ('name', 'slug', 'mcc', 'adolescent'):
            d[field] = getattr(o, field, None)
        return d

    data['regions'] = [serialize_region(REGIONS_CHOICES_ID_DICT.get(k))
                       for k in app.get_region_ids(
                           worldwide=True, excluded=obj.region_exclusions)]

    data['payment_account'] = None
    if src.get('premium_type') in amo.ADDON_PREMIUMS:
        try:
            acct = AddonPaymentAccount.objects.get(addon_id=src.get('id'))
            if acct.payment_account:
                data['payment_account'] = reverse(
                    'payment-account-detail',
                    kwargs={'pk': acct.payment_account.pk})
        except AddonPaymentAccount.DoesNotExist:
            pass  # Developer hasn't set up a payment account yet.

    data['upsell'] = False
    if hasattr(obj, 'upsell'):
        exclusions = obj.upsell.get('region_exclusions')
        if exclusions is not None and region_slug not in exclusions:
            data['upsell'] = obj.upsell
            data['upsell']['resource_uri'] = reverse(
                'app-detail',
                kwargs={'pk': obj.upsell['id']})

    data['price'] = data['price_locale'] = None
    try:
        price_tier = src.get('price_tier')
        if price_tier:
            price = Price.objects.get(name=price_tier)
            price_currency = price.get_price_currency(region=region_id)
            if price_currency and price_currency.paid:
                data['price'] = price.get_price(region=region_id)
                data['price_locale'] = price.get_price_locale(
                    region=region_id)
            data['payment_required'] = bool(price.price)
    except Price.DoesNotExist:
        log.warning('Issue with price tier on app: {0}'.format(obj._id))
        data['payment_required'] = True

    # TODO: Let's get rid of these from the API to avoid db hits.
    if profile and isinstance(profile, UserProfile):
        data['user'] = {
            'developed': AddonUser.objects.filter(
                addon=obj.id, user=profile,
                role=amo.AUTHOR_ROLE_OWNER).exists(),
            'installed': Installed.objects.filter(
                user=profile, addon_id=obj.id).exists(),
            'purchased': obj.id in profile.purchase_ids(),
        }

    return data
Beispiel #16
0
 def get_queryset(self):
     return Webapp.objects.all().exclude(
         id__in=get_excluded_in(REGIONS_DICT[get_region()].id))
Beispiel #17
0
def test_set_region_object():
    set_region(regions.USA)
    eq_(get_region(), regions.USA)
    set_region(regions.ESP)
    eq_(get_region(), regions.ESP)
Beispiel #18
0
def test_set_region(local):
    local.region = 'us'

    eq_(get_region(), 'us')
    set_region('es')
    eq_(get_region(), 'es')
Beispiel #19
0
def test_get_region_empty():
    eq_(get_region(), regions.RESTOFWORLD.slug)
    eq_(get_region_id(), regions.RESTOFWORLD.id)
Beispiel #20
0
def test_get_region_not_empty(local):
    local.region = 'us'

    eq_(get_region(), regions.US)
Beispiel #21
0
 def get_queryset(self):
     return Webapp.objects.all().exclude(
         id__in=get_excluded_in(REGIONS_DICT[get_region()].id))
Beispiel #22
0
 def get_queryset(self):
     return Webapp.objects.all().exclude(
         id__in=get_excluded_in(get_region().id))
Beispiel #23
0
def test_set_region(local):
    local.region = 'us'

    eq_(get_region(), regions.US)
    set_region('es')
    eq_(get_region(), regions.SPAIN)
Beispiel #24
0
def test_set_region(local):
    local.region = 'us'

    eq_(get_region(), regions.USA)
    set_region('es')
    eq_(get_region(), regions.ESP)
Beispiel #25
0
def test_set_region_object():
    set_region(regions.US)
    eq_(get_region(), regions.US)
    set_region(regions.SPAIN)
    eq_(get_region(), regions.SPAIN)
Beispiel #26
0
def test_set_region_bad_slug():
    set_region('foo')
    eq_(get_region(), regions.RESTOFWORLD)
Beispiel #27
0
 def get_queryset(self):
     return Webapp.objects.all().exclude(id__in=get_excluded_in(get_region().id))
Beispiel #28
0
def _filter_search(request, qs, query, filters=None, sorting=None,
                   sorting_default='-popularity', region=None, profile=None):
    """
    Filter an ES queryset based on a list of filters.

    If `profile` (a FeatureProfile object) is provided we filter by the
    profile. If you don't want to filter by these don't pass it. I.e. do the
    device detection for when this happens elsewhere.

    """
    # Intersection of the form fields present and the filters we want to apply.
    filters = filters or DEFAULT_FILTERS
    sorting = sorting or DEFAULT_SORTING
    show = filter(query.get, filters)

    if query.get('q'):
        qs = qs.query(should=True, **name_query(query['q'].lower()))
    if 'cat' in show:
        qs = qs.filter(category=query['cat'])
    if 'price' in show:
        if query['price'] == 'paid':
            qs = qs.filter(premium_type__in=amo.ADDON_PREMIUMS)
        elif query['price'] == 'free':
            qs = qs.filter(premium_type__in=amo.ADDON_FREES, price=0)
    if 'device' in show:
        qs = qs.filter(device=forms.DEVICE_CHOICES_IDS[query['device']])
    if 'premium_types' in show:
        if query.get('premium_types'):
            qs = qs.filter(premium_type__in=query.get('premium_types'))
    if 'app_type' in query and query['app_type']:
        qs = qs.filter(app_type=query['app_type'])
    if 'sort' in show:
        sort_by = None
        if query['sort'] in sorting:
            sort_by = sorting[query['sort']]

        # For "Adolescent" regions popularity is global installs + reviews.

        if query['sort'] == 'popularity' and region and not region.adolescent:
            # For "Mature" regions popularity becomes installs + reviews
            # from only that region.
            sort_by = '-popularity_%s' % region.id

        if sort_by:
            qs = qs.order_by(sort_by)
    elif not query.get('q'):

        if (sorting_default == 'popularity' and region and
            not region.adolescent):
            # For "Mature" regions popularity becomes installs + reviews
            # from only that region.
            sorting_default = '-popularity_%s' % region.id

        # Sort by a default if there was no query so results are predictable.
        qs = qs.order_by(sorting_default)

    region = regions.REGIONS_DICT[get_region()]
    # If the region only supports carrier billing for app purchase,
    # don't list apps that require carrier billing to buy.
    if not region.supports_carrier_billing:
        qs = qs.filter(carrier_billing_only=False)

    if profile and waffle.switch_is_active('buchets'):
        f = F()
        for k, v in profile.iteritems():
            if not v:
                f &= F(**{'features.has_%s' % k: False})
        qs = qs.filter(f)

    return qs