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)
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)
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
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
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
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): 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 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
def test_get_region_worldwide(local): local.region = 'worldwide' eq_(get_region(), regions.RESTOFWORLD)
def test_get_region_empty(): eq_(get_region(), regions.WORLDWIDE.slug) eq_(get_region_id(), regions.WORLDWIDE.id)
def test_set_region(local): local.region = 'us' eq_(get_region(), 'us') set_region('es') eq_(get_region(), 'es')
def test_get_region_empty(): eq_(get_region(), regions.RESTOFWORLD)
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
def get_queryset(self): return Webapp.objects.all().exclude( id__in=get_excluded_in(REGIONS_DICT[get_region()].id))
def test_set_region_object(): set_region(regions.USA) eq_(get_region(), regions.USA) set_region(regions.ESP) eq_(get_region(), regions.ESP)
def test_get_region_empty(): eq_(get_region(), regions.RESTOFWORLD.slug) eq_(get_region_id(), regions.RESTOFWORLD.id)
def test_get_region_not_empty(local): local.region = 'us' eq_(get_region(), regions.US)
def get_queryset(self): return Webapp.objects.all().exclude( id__in=get_excluded_in(get_region().id))
def test_set_region(local): local.region = 'us' eq_(get_region(), regions.US) set_region('es') eq_(get_region(), regions.SPAIN)
def test_set_region(local): local.region = 'us' eq_(get_region(), regions.USA) set_region('es') eq_(get_region(), regions.ESP)
def test_set_region_object(): set_region(regions.US) eq_(get_region(), regions.US) set_region(regions.SPAIN) eq_(get_region(), regions.SPAIN)
def test_set_region_bad_slug(): set_region('foo') eq_(get_region(), regions.RESTOFWORLD)
def get_queryset(self): return Webapp.objects.all().exclude(id__in=get_excluded_in(get_region().id))
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