def extract_filters(term, app_id=amo.FIREFOX.id, opts=None): """ Pulls all the filtering options out of the term and returns a cleaned term and a dictionary of filter names and filter values. Term filters override filters found in opts. """ opts = opts or {} filters = {} # Type filters. term, addon_type = extract_from_query(term, 'type', '\w+') addon_type = addon_type or opts.get('addon_type') if addon_type: try: atype = int(addon_type) if atype in amo.get_addon_search_types(): filters['type'] = atype except ValueError: # `addon_type` is not a digit. Try to find it in ADDON_SEARCH_SLUGS. atype = amo.ADDON_SEARCH_SLUGS.get(addon_type.lower()) if atype: filters['type'] = atype # Platform filters. term, platform = extract_from_query(term, 'platform', '\w+') platform = platform or opts.get('platform') if platform: platform = [ amo.PLATFORM_DICT.get(platform.lower(), amo.PLATFORM_ALL).id ] if amo.PLATFORM_ALL.id not in platform: platform.append(amo.PLATFORM_ALL.id) filters['platform__in'] = platform # Version filters. term, version = extract_from_query(term, 'version', '[0-9.]+') version = version or opts.get('version') if version: filters.update(filter_version(version, app_id)) # Category filters. term, category = extract_from_query(term, 'category', '\w+') if category and 'app' in opts: category = (Category.objects.filter( slug__istartswith=category, application=opts['app']).values_list('id', flat=True)) if category: filters['category'] = category[0] # Tag filters. term, tag = extract_from_query(term, 'tag', '\w+') if tag: tag = Tag.objects.filter(tag_text=tag).values_list('tag_text', flat=True) if tag: filters['tags__in'] = list(tag) return (term, filters)
def extract_filters(term, app_id=amo.FIREFOX.id, opts=None): """ Pulls all the filtering options out of the term and returns a cleaned term and a dictionary of filter names and filter values. Term filters override filters found in opts. """ opts = opts or {} filters = {} # Type filters. term, addon_type = extract_from_query(term, 'type', '\w+') addon_type = addon_type or opts.get('addon_type') if addon_type: try: atype = int(addon_type) if atype in amo.get_addon_search_types(): filters['type'] = atype except ValueError: # `addon_type` is not a digit. Try to find it in ADDON_SEARCH_SLUGS. atype = amo.ADDON_SEARCH_SLUGS.get(addon_type.lower()) if atype: filters['type'] = atype # Platform filters. term, platform = extract_from_query(term, 'platform', '\w+') platform = platform or opts.get('platform') if platform: platform = [amo.PLATFORM_DICT.get(platform.lower(), amo.PLATFORM_ALL).id] if amo.PLATFORM_ALL.id not in platform: platform.append(amo.PLATFORM_ALL.id) filters['platform__in'] = platform # Version filters. term, version = extract_from_query(term, 'version', '[0-9.]+') version = version or opts.get('version') if version: filters.update(filter_version(version, app_id)) # Category filters. term, category = extract_from_query(term, 'category', '\w+') if category and 'app' in opts: category = (Category.objects.filter(slug__istartswith=category, application=opts['app']) .values_list('id', flat=True)) if category: filters['category'] = category[0] # Tag filters. term, tag = extract_from_query(term, 'tag', '\w+') if tag: tag = Tag.objects.filter(tag_text=tag).values_list('tag_text', flat=True) if tag: filters['tags__in'] = list(tag) return (term, filters)
def process_request(self, query, addon_type='ALL', limit=10, platform='ALL', version=None, compat_mode='strict'): """ Query the search backend and serve up the XML. """ limit = min(MAX_LIMIT, int(limit)) app_id = self.request.APP.id filters = { 'app': app_id, 'status__in': amo.REVIEWED_STATUSES, 'is_disabled': False, 'has_version': True, } # Opts may get overridden by query string filters. opts = { 'addon_type': addon_type, 'platform': platform, 'version': version, } if self.version < 1.5: # By default we show public addons only for api_version < 1.5. filters['status__in'] = [amo.STATUS_PUBLIC] # Fix doubly encoded query strings. try: query = urllib.unquote(query.encode('ascii')) except UnicodeEncodeError: # This fails if the string is already UTF-8. pass query, qs_filters = extract_filters(query, filters['app'], opts) qs = Addon.search().query(or_=name_query(query)) filters.update(qs_filters) if 'type' not in filters: # Filter by ALL types, which is really all types except for apps. filters['type__in'] = list(amo.get_addon_search_types()) qs = qs.filter(**filters) addons = qs[:limit] total = qs.count() if waffle.switch_is_active('d2c-api-search'): is_d2c = True results = [] for addon in qs: compat_version = addon.compatible_version(app_id, version, platform, compat_mode) if compat_version: addon.compat_version = compat_version results.append(addon) if len(results) == limit: break else: # We're excluding this addon because there are no # compatible versions. Decrement the total. total -= 1 else: is_d2c = False results = addons return self.render('api/search.xml', { 'is_d2c': is_d2c, 'results': results, 'total': total, # For caching 'version': version, 'compat_mode': compat_mode, })
class _SearchForm(SimpleSearchForm): cat = forms.ChoiceField(choices=search_groups, required=False) # This gets replaced by a <select> with js. lver = forms.ChoiceField( # L10n: {0} is the name of an app. Ex: Firefox label=_lazy(u'{0} Version').format(unicode(current_app.pretty)), choices=get_app_versions(current_app), required=False) appver = forms.CharField(required=False) atype = forms.TypedChoiceField( label=_lazy(u'Type'), choices=[(t, amo.ADDON_TYPE[t]) for t in amo.get_addon_search_types()], required=False, coerce=int, empty_value=amo.ADDON_ANY) pid = forms.TypedChoiceField(label=_lazy(u'Platform'), choices=[ (p[0], p[1].name) for p in amo.PLATFORMS.iteritems() if p[1] != amo.PLATFORM_ANY ], required=False, coerce=int, empty_value=amo.PLATFORM_ANY.id) platform = forms.ChoiceField(required=False, choices=[[p.shortname, p.id] for p in amo.PLATFORMS.values()]) sort = forms.ChoiceField(label=_lazy(u'Sort By'), choices=sort_by, required=False) pp = forms.TypedChoiceField(label=_lazy(u'Per Page'), choices=zip(per_page, per_page), required=False, coerce=int, empty_value=per_page[0]) advanced = forms.BooleanField(widget=forms.HiddenInput, required=False) tag = forms.CharField(widget=forms.HiddenInput, required=False) page = forms.IntegerField(widget=forms.HiddenInput, required=False) # Attach these to the form for usage in the template. top_level_cat = dict(top_level) def clean_platform(self): p = self.cleaned_data.get('platform') choices = dict(self.fields['platform'].choices) return choices.get(p) # TODO(jbalogh): when we start using this form for zamboni search, it # should check that the appid and lver match up using app_versions. def clean(self): d = self.cleaned_data raw = self.data # Set some defaults if not d.get('appid'): d['appid'] = request.APP.id # Since not all categories are listed in this form, we use the raw # data. if 'cat' in raw: if ',' in raw['cat']: try: d['atype'], d['cat'] = map(int, raw['cat'].split(',')) except ValueError: d['cat'] = None elif raw['cat'] == 'all': d['cat'] = None if 'page' not in d or not d['page'] or d['page'] < 1: d['page'] = 1 return d def full_clean(self): """ Cleans all of self.data and populates self._errors and self.cleaned_data. Does not remove cleaned_data if there are errors. """ self._errors = ErrorDict() if not self.is_bound: # Stop further processing. return self.cleaned_data = {} # If the form is permitted to be empty, and none of the form data # has changed from the initial data, short circuit any validation. if self.empty_permitted and not self.has_changed(): return self._clean_fields() self._clean_form()
def process_request(self, query, addon_type='ALL', limit=10, platform='ALL', version=None, compat_mode='strict'): """ Query the search backend and serve up the XML. """ limit = min(MAX_LIMIT, int(limit)) app_id = self.request.APP.id filters = { 'app': app_id, 'status__in': amo.REVIEWED_STATUSES, 'is_disabled': False, 'has_version': True, } # Opts may get overridden by query string filters. opts = { 'addon_type': addon_type, 'platform': platform, 'version': version, } if self.version < 1.5: # By default we show public addons only for api_version < 1.5. filters['status__in'] = [amo.STATUS_PUBLIC] # Fix doubly encoded query strings. try: query = urllib.unquote(query.encode('ascii')) except UnicodeEncodeError: # This fails if the string is already UTF-8. pass query, qs_filters = extract_filters(query, filters['app'], opts) qs = Addon.search().query(or_=name_query(query)) filters.update(qs_filters) if 'type' not in filters: # Filter by ALL types, which is really all types except for apps. filters['type__in'] = list(amo.get_addon_search_types()) qs = qs.filter(**filters) addons = qs[:limit] total = qs.count() if waffle.switch_is_active('d2c-api-search'): is_d2c = True results = [] for addon in qs: compat_version = addon.compatible_version( app_id, version, platform, compat_mode) if compat_version: addon.compat_version = compat_version results.append(addon) if len(results) == limit: break else: # We're excluding this addon because there are no # compatible versions. Decrement the total. total -= 1 else: is_d2c = False results = addons return self.render( 'api/search.xml', { 'is_d2c': is_d2c, 'results': results, 'total': total, # For caching 'version': version, 'compat_mode': compat_mode, })