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:
Родитель
645abccd81
Коммит
e744e269d3
|
@ -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']
|
||||||
|
|
Загрузка…
Ссылка в новой задаче