Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow deactivating the language filter when searching for ingredients and exercises #1687

Merged
merged 5 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions wger/core/templates/navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@
{% translate "Daily calories calculator" %}
</a>
</li>
<li>
<a class="dropdown-item" href="{% url 'nutrition:ingredient:list' %}">
{% translate "Ingredient overview" %}
</a>
</li>
{% if perms.nutrition %}
<li class="dropdown-divider"></li>
<li class="dropdown-header">{% translate "Administration" %}</li>
Expand All @@ -182,11 +187,6 @@
{% translate "Ingredient weight units" %}
</a>
</li>
<li>
<a class="dropdown-item" href="{% url 'nutrition:ingredient:list' %}">
{% translate "Ingredient overview" %}
</a>
</li>
{% endif %}
</ul>
</li>
Expand Down
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)
9 changes: 5 additions & 4 deletions wger/nutrition/views/ingredient.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
)
from wger.utils.language import load_language


logger = logging.getLogger(__name__)


Expand All @@ -83,15 +82,17 @@ def get_queryset(self):
return Ingredient.objects.filter(language=language)


# Cache for one week
@cache_page(settings.WGER_SETTINGS['INGREDIENT_CACHE_TTL'])
def view(request, pk, slug=None):
context = {}

ingredient = cache.get(cache_mapper.get_ingredient_key(int(pk)))
if not ingredient:
ingredient = get_object_or_404(Ingredient, pk=pk)
cache.set(cache_mapper.get_ingredient_key(ingredient), ingredient)
cache.set(
cache_mapper.get_ingredient_key(ingredient),
ingredient,
settings.WGER_SETTINGS['INGREDIENT_CACHE_TTL'],
)
context['ingredient'] = ingredient
context['image'] = ingredient.get_image(request)
context['form'] = UnitChooserForm(
Expand Down
4 changes: 2 additions & 2 deletions wger/settings.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ DATABASES = {{
}} # yapf: disable

# List of administrations
ADMINS = (('Your name', '[email protected]'), )
ADMINS = (('Your name', '[email protected]'),)
MANAGERS = ADMINS

# SERVER_EMAIL = '[email protected]'
Expand All @@ -44,7 +44,7 @@ SECRET_KEY = '{default_key}'
# Your reCaptcha keys
RECAPTCHA_PUBLIC_KEY = ''
RECAPTCHA_PRIVATE_KEY = ''
NOCAPTCHA = True
USE_RECAPTCHA = False

# The site's URL (e.g. http://www.my-local-gym.com or http://localhost:8000)
# This is needed for uploaded files and images (exercise images, etc.) to be
Expand Down
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 = '*'
Loading