Skip to content

Commit

Permalink
Merge pull request #1687 from wger-project/feature/language-filter
Browse files Browse the repository at this point in the history
Allow deactivating the language filter when searching for ingredients and exercises
  • Loading branch information
rolandgeider authored Jul 7, 2024
2 parents 06e9b99 + f49f81b commit 0049de3
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 16 deletions.
9 changes: 8 additions & 1 deletion wger/exercises/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
HTML_ATTRIBUTES_WHITELIST,
HTML_STYLES_WHITELIST,
HTML_TAG_WHITELIST,
SEARCH_ALL_LANGUAGES,
)
from wger.utils.db import is_postgres_db
from wger.utils.language import load_language
Expand Down Expand Up @@ -346,8 +347,14 @@ def search(request):
if not q:
return Response(response)

# Filter the appropriate languages
languages = [load_language(l) for l in language_codes.split(',')]
query = Exercise.objects.filter(language__in=languages).only('name')
if language_codes == SEARCH_ALL_LANGUAGES:
query = Exercise.objects.all()
else:
query = Exercise.objects.filter(language__in=languages)

query = query.only('name')

# Postgres uses a full-text search
if is_postgres_db():
Expand Down
9 changes: 9 additions & 0 deletions wger/exercises/tests/test_search_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,12 @@ def test_search_several_language_codes(self):

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 4)

def test_search_all_languages(self):
"""
Passing different language codes works correctly
"""
response = self.client.get(self.url + '?term=demo&language=*')

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 4)
27 changes: 17 additions & 10 deletions wger/nutrition/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from django.contrib.postgres.search import TrigramSimilarity
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page

# Third Party
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
Expand Down Expand Up @@ -73,12 +72,14 @@
NutritionPlan,
WeightUnit,
)
from wger.utils.constants import ENGLISH_SHORT_NAME
from wger.utils.constants import (
ENGLISH_SHORT_NAME,
SEARCH_ALL_LANGUAGES,
)
from wger.utils.db import is_postgres_db
from wger.utils.language import load_language
from wger.utils.viewsets import WgerOwnerObjectModelViewSet


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -211,15 +212,21 @@ def search(request):
term = request.GET.get('term', None)
language_codes = request.GET.get('language', ENGLISH_SHORT_NAME)
results = []
json_response = {}
response = {}

if not term:
return Response(json_response)
return Response(response)

query = Ingredient.objects.all()

# Filter the appropriate languages
languages = [load_language(l) for l in language_codes.split(',')]
query = Ingredient.objects.filter(
language__in=languages,
).only('name')
if language_codes != SEARCH_ALL_LANGUAGES:
query = query.filter(
language__in=languages,
)

query = query.only('name')

# Postgres uses a full-text search
if is_postgres_db():
Expand Down Expand Up @@ -252,9 +259,9 @@ def search(request):
},
}
results.append(ingredient_json)
json_response['suggestions'] = results
response['suggestions'] = results

return Response(json_response)
return Response(response)


class ImageViewSet(viewsets.ReadOnlyModelViewSet):
Expand Down
8 changes: 4 additions & 4 deletions wger/nutrition/fixtures/test-ingredients.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@
"license_author": "wger test",
"last_update": "2013-02-12T01:00:00+01:00",
"created": "2013-04-05T01:00:00+01:00",
"name": "Raw ingredient",
"language": 2,
"name": "Testzutat 123",
"language": 1,
"sodium": "2.1",
"energy": 180,
"fat": "2",
Expand Down Expand Up @@ -333,7 +333,7 @@
"last_update": "2013-02-12T01:00:00+01:00",
"created": "2013-04-05T01:00:00+01:00",
"name": "Needed for guest user",
"language": 2,
"language": 3,
"sodium": "2.1",
"energy": 180,
"fat": "2",
Expand All @@ -360,7 +360,7 @@
"last_update": "2013-02-12T01:00:00+01:00",
"created": "2013-04-05T01:00:00+01:00",
"name": "Needed for guest user",
"language": 2,
"language": 3,
"sodium": "2.1",
"energy": 180,
"fat": "2",
Expand Down
2 changes: 1 addition & 1 deletion wger/nutrition/tests/test_ingredient_overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_overview(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context['ingredients_list']), PAGINATION_OBJECTS_PER_PAGE)

rest_ingredients = 14
rest_ingredients = 11
response = self.client.get(reverse('nutrition:ingredient:list'), {'page': 3})
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context['ingredients_list']), rest_ingredients)
Expand Down
114 changes: 114 additions & 0 deletions wger/nutrition/tests/test_search_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# This file is part of wger Workout Manager.
#
# wger Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# wger Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.

# Third Party
from rest_framework import status

# wger
from wger.core.tests.api_base_test import ApiBaseTestCase
from wger.core.tests.base_testcase import BaseTestCase


class SearchIngredientApiTestCase(BaseTestCase, ApiBaseTestCase):
url = '/api/v2/ingredient/search/'

def setUp(self):
super().setUp()
self.init_media_root()

def test_basic_search_logged_out(self):
"""
Logged-out users are also allowed to use the search
"""
response = self.client.get(self.url + '?term=test')
result1 = response.data['suggestions'][0]

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 2)
self.assertEqual(result1['value'], 'Ingredient, test, 2, organic, raw')
self.assertEqual(result1['data']['id'], 2)

def test_basic_search_logged_in(self):
"""
Logged-in users get the same results
"""
self.authenticate('test')
response = self.client.get(self.url + '?term=test')
result1 = response.data['suggestions'][0]

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 2)
self.assertEqual(result1['value'], 'Ingredient, test, 2, organic, raw')
self.assertEqual(result1['data']['id'], 2)

def test_search_language_code_en(self):
"""
Explicitly passing the en language code (same as no code)
"""
response = self.client.get(self.url + '?term=test&language=en')
result1 = response.data['suggestions'][0]

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 2)
self.assertEqual(result1['value'], 'Ingredient, test, 2, organic, raw')
self.assertEqual(result1['data']['id'], 2)

def test_search_language_code_en_no_results(self):
"""
The "Testzutat" ingredient should not be found when searching in English
"""
response = self.client.get(self.url + '?term=Testzutat&language=en')

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 0)

def test_search_language_code_de(self):
"""
The "Testübung" exercise should be only found when searching in German
"""
response = self.client.get(self.url + '?term=Testzutat&language=de')
result1 = response.data['suggestions'][0]

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 1)
self.assertEqual(result1['value'], 'Testzutat 123')
self.assertEqual(result1['data']['id'], 6)

def test_search_several_language_codes(self):
"""
Passing different language codes works correctly
"""
response = self.client.get(self.url + '?term=guest&language=en,de')

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 5)

def test_search_unknown_language_codes(self):
"""
Unknown language codes are ignored
"""
response = self.client.get(self.url + '?term=guest&language=en,de,kg')

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 5)

def test_search_all_languages(self):
"""
Disable all language filters
"""
response = self.client.get(self.url + '?term=guest&language=*')

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['suggestions']), 7)
1 change: 1 addition & 0 deletions wger/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@

# API
API_MAX_ITEMS = 999
SEARCH_ALL_LANGUAGES = '*'

0 comments on commit 0049de3

Please sign in to comment.