Handle Non-Alphanumerical Edge Cases When Searching Themes By Colour (#22699)

* Introduce convert_to_hex function for color queries on search for themes

* make convert_to_hex use hexadecimal rather than alphanumeric, more explicit ValueError

* testing

* lint
This commit is contained in:
Christina Lin 2024-09-25 08:58:35 -04:00 коммит произвёл GitHub
Родитель 645abccd81
Коммит e744e269d3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 33 добавлений и 4 удалений

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

@ -1,3 +1,4 @@
import re
from datetime import datetime from datetime import datetime
from django.utils import translation from django.utils import translation
@ -433,13 +434,21 @@ class AddonPromotedQueryParam(AddonQueryMultiParam):
class AddonColorQueryParam(AddonQueryParam): class AddonColorQueryParam(AddonQueryParam):
query_param = 'color' query_param = 'color'
def convert_to_hsl(self, hexvalue): def convert_to_hex(self, color):
color = re.sub(r'[^0-9A-Fa-f]', '', color)[:6]
if len(color) == 3:
color = ''.join(2 * c for c in color)
if len(color) != 6:
raise ValueError
else:
return color
def convert_to_hsl(self, color):
# The API is receiving color as a hex string. We store colors in HSL # The API is receiving color as a hex string. We store colors in HSL
# as colorgram generates it (which is on a 0 to 255 scale for each # as colorgram generates it (which is on a 0 to 255 scale for each
# component), so some conversion is necessary. # component), so some conversion is necessary.
if len(hexvalue) == 3:
hexvalue = ''.join(2 * c for c in hexvalue)
try: try:
hexvalue = self.convert_to_hex(color)
rgb = tuple(bytearray.fromhex(hexvalue)) rgb = tuple(bytearray.fromhex(hexvalue))
except ValueError as err: except ValueError as err:
raise ValueError( raise ValueError(
@ -449,7 +458,7 @@ class AddonColorQueryParam(AddonQueryParam):
def get_value(self): def get_value(self):
color = self.query_data.get(self.query_param, '') color = self.query_data.get(self.query_param, '')
return self.convert_to_hsl(color.upper().lstrip('#')[:6]) if color else None return self.convert_to_hsl(color) if color else None
def get_es_query(self): def get_es_query(self):
# Thresholds for saturation & luminosity that dictate which query to # Thresholds for saturation & luminosity that dictate which query to

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

@ -1048,6 +1048,18 @@ class TestSearchParameterFilter(FilterTestsBase):
{'range': {'colors.ratio': {'gte': 0.25}}}, {'range': {'colors.ratio': {'gte': 0.25}}},
] ]
qs = self._filter(data={'color': '00$#ff*$ff'})
filter_ = qs['query']['bool']['filter']
assert len(filter_) == 1
inner = filter_[0]['nested']['query']['bool']['filter']
assert len(inner) == 4
assert inner == [
{'range': {'colors.s': {'gt': 6.375}}},
{'range': {'colors.l': {'gt': 12.75, 'lt': 249.9}}},
{'range': {'colors.h': {'gte': 101, 'lte': 153}}},
{'range': {'colors.ratio': {'gte': 0.25}}},
]
def test_search_by_color_grey(self): def test_search_by_color_grey(self):
qs = self._filter(data={'color': '#f6f6f6'}) qs = self._filter(data={'color': '#f6f6f6'})
filter_ = qs['query']['bool']['filter'] filter_ = qs['query']['bool']['filter']
@ -1081,6 +1093,14 @@ class TestSearchParameterFilter(FilterTestsBase):
self._filter(data={'color': '#gggggg'}) self._filter(data={'color': '#gggggg'})
assert context.exception.detail == ['Invalid "color" parameter.'] assert context.exception.detail == ['Invalid "color" parameter.']
with self.assertRaises(serializers.ValidationError) as context:
self._filter(data={'color': '#$(@#*)'})
assert context.exception.detail == ['Invalid "color" parameter.']
with self.assertRaises(serializers.ValidationError) as context:
self._filter(data={'color': ' '})
assert context.exception.detail == ['Invalid "color" parameter.']
def test_search_by_color_luminosity_extremes(self): def test_search_by_color_luminosity_extremes(self):
qs = self._filter(data={'color': '080603'}) qs = self._filter(data={'color': '080603'})
filter_ = qs['query']['bool']['filter'] filter_ = qs['query']['bool']['filter']