Decode guid using base64 if prefixed by rta: in search API

This supports the "Return to AMO" feature from bug 1468680.
This commit is contained in:
Mathieu Pillard 2018-12-17 14:23:29 +01:00
Родитель 196795c046
Коммит 4be0ca4973
4 изменённых файлов: 63 добавлений и 3 удалений

Просмотреть файл

@ -50,7 +50,7 @@ This endpoint allows you to search through public add-ons.
:query boolean featured: Filter to only featured add-ons. Only ``featured=true`` is supported. :query boolean featured: Filter to only featured add-ons. Only ``featured=true`` is supported.
If ``app`` is provided as a parameter then only featured collections targeted to that application are taken into account. If ``app`` is provided as a parameter then only featured collections targeted to that application are taken into account.
If ``lang`` is provided then only featured collections targeted to that language, (and collections for all languages), are taken into account. Both ``app`` and ``lang`` can be provided to filter to addons that are featured in collections that application and for that language, (and for all languages). If ``lang`` is provided then only featured collections targeted to that language, (and collections for all languages), are taken into account. Both ``app`` and ``lang`` can be provided to filter to addons that are featured in collections that application and for that language, (and for all languages).
:query string guid: Filter by exact add-on guid. Multiple guids can be specified, separated by comma(s), in which case any add-ons matching any of the guids will be returned. As guids are unique there should be at most one add-on result per guid specified. :query string guid: Filter by exact add-on guid. Multiple guids can be specified, separated by comma(s), in which case any add-ons matching any of the guids will be returned. As guids are unique there should be at most one add-on result per guid specified. For usage with Firefox, instead of separating multiple guids by comma(s), a single guid can be passed in base64url format, prefixed by the ``rta:`` string.
:query string lang: Activate translations in the specific language for that query. (See :ref:`translated fields <api-overview-translations>`) :query string lang: Activate translations in the specific language for that query. (See :ref:`translated fields <api-overview-translations>`)
:query int page: 1-based page number. Defaults to 1. :query int page: 1-based page number. Defaults to 1.
:query int page_size: Maximum number of results to return for the requested page. Defaults to 25. :query int page_size: Maximum number of results to return for the requested page. Defaults to 25.

Просмотреть файл

@ -7,7 +7,7 @@ from django.conf import settings
from django.core import mail from django.core import mail
from django.test.utils import override_settings from django.test.utils import override_settings
from django.test.client import Client from django.test.client import Client
from django.utils.http import urlunquote from django.utils.http import urlsafe_base64_encode, urlunquote
import mock import mock
import pytest import pytest
@ -2864,6 +2864,42 @@ class TestAddonSearchView(ESTestCase):
assert data['results'][0]['id'] == addon.pk assert data['results'][0]['id'] == addon.pk
assert data['results'][1]['id'] == addon2.pk assert data['results'][1]['id'] == addon2.pk
def test_filter_by_guid_return_to_amo(self):
addon = addon_factory(slug='my-addon', name=u'My Addôn',
guid='random@guid', weekly_downloads=999)
addon_factory()
self.reindex(Addon)
param = 'rta:%s' % urlsafe_base64_encode(addon.guid)
data = self.perform_search(self.url, {'guid': param})
assert data['count'] == 1
assert len(data['results']) == 1
result = data['results'][0]
assert result['id'] == addon.pk
assert result['slug'] == addon.slug
def test_filter_by_guid_return_to_amo_wrong_format(self):
param = 'rta:%s' % urlsafe_base64_encode('foo@bar')[:-1]
data = self.perform_search(
self.url, {'guid': param}, expected_status=400)
assert data == [u'Invalid RTA guid (not base64url?)']
@override_settings(RETURN_TO_AMO=False)
def test_filter_by_guid_return_to_amo_feature_disabled(self):
addon = addon_factory(slug='my-addon', name=u'My Addôn',
guid='random@guid', weekly_downloads=999)
addon_factory()
self.reindex(Addon)
param = 'rta:%s' % urlsafe_base64_encode(addon.guid)
data = self.perform_search(
self.url, {'guid': param}, expected_status=400)
assert data == [u'RTA is currently disabled']
def test_find_addon_default_non_en_us(self): def test_find_addon_default_non_en_us(self):
with self.activate('en-GB'): with self.activate('en-GB'):
addon = addon_factory( addon = addon_factory(

Просмотреть файл

@ -1788,6 +1788,12 @@ DRF_API_GATES = {
), ),
} }
# Return to AMO (https://bugzilla.mozilla.org/show_bug.cgi?id=1468680)
# kill switch. RETURN_TO_AMO=0 env variable deactivates it, causing the API to
# return 400s when the feature is used.
RETURN_TO_AMO = env('RETURN_TO_AMO', default=True)
# Change this to deactivate API throttling for views using a throttling class # Change this to deactivate API throttling for views using a throttling class
# depending on the one defined in olympia.api.throttling. # depending on the one defined in olympia.api.throttling.
API_THROTTLING = True API_THROTTLING = True

Просмотреть файл

@ -1,4 +1,6 @@
from django.conf import settings
from django.utils import translation from django.utils import translation
from django.utils.http import urlsafe_base64_decode
from django.utils.translation import ugettext from django.utils.translation import ugettext
import colorgram import colorgram
@ -135,7 +137,23 @@ class AddonGuidQueryParam(AddonQueryParam):
es_field = 'guid' es_field = 'guid'
def get_value(self): def get_value(self):
value = self.request.GET.get(self.query_param) value = self.request.GET.get(self.query_param, '')
# Hack for Firefox 'return to AMO' feature (which, sadly, does not use
# a specific API but rather encodes the guid and adds a prefix to it,
# only in the search API): if the guid param matches this format, and
# the feature is enabled through a setting, then we decode it and
# proceed. A 400 is returned if the format is recognized but the
# feature is disabled through the setting, acting as a kill-switch.
if value.startswith('rta:') and '@' not in value:
if settings.RETURN_TO_AMO is not True:
raise ValueError('RTA is currently disabled')
# Any ValueError will trigger a 400.
try:
value = urlsafe_base64_decode(value[4:])
except TypeError:
raise ValueError('Invalid RTA guid (not base64url?)')
return value.split(',') if value else [] return value.split(',') if value else []