From 7a9f9415c19c290be441946b2ec4952f6b98344e Mon Sep 17 00:00:00 2001 From: David Wallace Date: Tue, 4 Jul 2023 17:04:13 +0200 Subject: [PATCH 01/24] add REPLACE_MISSING_TRANSLATION feature flag to TranslationMixin for #614 --- rdmo/core/models.py | 3 ++- rdmo/core/settings.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rdmo/core/models.py b/rdmo/core/models.py index d04cd27428..9ac75d4cc4 100644 --- a/rdmo/core/models.py +++ b/rdmo/core/models.py @@ -1,5 +1,6 @@ import logging +from django.conf import settings from django.db import models from django.utils.timezone import now from django.utils.translation import get_language @@ -38,7 +39,7 @@ def trans(self, field): r = getattr(self, '%s_%s' % (field, lang_field)) or None if r is not None: return r - else: + elif settings.REPLACE_MISSING_TRANSLATION: for i in range(1, 6): r = getattr(self, '%s_%s' % (field, 'lang' + str(i))) or None if r is not None: diff --git a/rdmo/core/settings.py b/rdmo/core/settings.py index 45bfc22294..472a5604b8 100644 --- a/rdmo/core/settings.py +++ b/rdmo/core/settings.py @@ -307,6 +307,8 @@ DEFAULT_URI_PREFIX = 'http://example.com/terms' +REPLACE_MISSING_TRANSLATION = False + VENDOR_CDN = True VENDOR = { From f0a73065aa2c284c79b7a533ae2c2a8124d4097b Mon Sep 17 00:00:00 2001 From: David Wallace Date: Wed, 5 Jul 2023 22:48:24 +0200 Subject: [PATCH 02/24] add tests for TranslationMixin.trans method --- rdmo/core/tests/test_models.py | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 rdmo/core/tests/test_models.py diff --git a/rdmo/core/tests/test_models.py b/rdmo/core/tests/test_models.py new file mode 100644 index 0000000000..50b27adcf8 --- /dev/null +++ b/rdmo/core/tests/test_models.py @@ -0,0 +1,63 @@ +import pytest + +from django.utils.translation import get_language + +from rdmo.core.models import TranslationMixin +from rdmo.core.utils import get_languages + +boolean_toggle = (True, False) +test_languages = ('en', 'de') + +test_lang_mapper = { + 'en': { + 'title': 'title_lang1', + 'text': 'text_lang1' + }, + 'de': { + 'title': 'title_lang2', + 'text': 'text_lang2' + } +} + +class TestTranslationModel(TranslationMixin): + + title_lang1 = 'title-1' + title_lang2 = 'title-2' + + text_lang1 = 'text-1' + text_lang2 = 'text-2' + + + +@pytest.mark.parametrize('test_setting', boolean_toggle) +@pytest.mark.parametrize('test_lang', test_languages) +def test_translationmixin_trans(settings, test_setting, test_lang): + settings.REPLACE_MISSING_TRANSLATION = test_setting + + settings.LANGUAGE_CODE = test_lang + instance = TestTranslationModel() + # trans should return the correct value + assert instance.trans('title') == getattr(instance, test_lang_mapper[test_lang]['title']) + assert instance.trans('text') == getattr(instance, test_lang_mapper[test_lang]['text']) + del instance + +@pytest.mark.parametrize('test_setting', boolean_toggle) +@pytest.mark.parametrize('test_lang', test_languages) +def test_translationmixin_trans_empty_field(settings, test_setting, test_lang): + settings.REPLACE_MISSING_TRANSLATION = test_setting + empty_lang = 'en' + + settings.LANGUAGE_CODE = test_lang + instance = TestTranslationModel() + instance.title_lang1 = '' + instance.text_lang1 = '' + + other_lang = 'de' if test_lang == 'en' else 'en' + + if test_lang == empty_lang and settings.REPLACE_MISSING_TRANSLATION: + assert instance.trans('title') == getattr(instance, test_lang_mapper[other_lang]['title']) + assert instance.trans('text') == getattr(instance, test_lang_mapper[other_lang]['text']) + else: + assert instance.trans('title') == getattr(instance, test_lang_mapper[test_lang]['title']) + assert instance.trans('text') == getattr(instance, test_lang_mapper[test_lang]['text']) + del instance From 0a291600a71687339efa0a06e6e876dd16e2b72e Mon Sep 17 00:00:00 2001 From: David Wallace Date: Thu, 6 Jul 2023 03:58:26 +0200 Subject: [PATCH 03/24] [feat] #629 change appearance of unavailable catalogs in project create form view --- rdmo/projects/forms.py | 5 ++ rdmo/projects/tests/test_view_project.py | 83 ++++++++++++++++++++---- rdmo/projects/views/project_create.py | 3 +- rdmo/questions/tests/test_models.py | 26 ++++++++ 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/rdmo/projects/forms.py b/rdmo/projects/forms.py index 9bf14d2421..7ef1761f3a 100644 --- a/rdmo/projects/forms.py +++ b/rdmo/projects/forms.py @@ -18,7 +18,12 @@ class CatalogChoiceField(forms.ModelChoiceField): + _unavailable_icon = ' ()' + def label_from_instance(self, obj): + if obj.available is False: + return mark_safe('
%s%s
%s
' % (obj.title, self._unavailable_icon, markdown2html(obj.help))) + return mark_safe('%s
%s' % (obj.title, markdown2html(obj.help))) diff --git a/rdmo/projects/tests/test_view_project.py b/rdmo/projects/tests/test_view_project.py index 1c48b5d985..9c70f30d96 100644 --- a/rdmo/projects/tests/test_view_project.py +++ b/rdmo/projects/tests/test_view_project.py @@ -4,8 +4,11 @@ from django.urls import reverse from pytest_django.asserts import assertTemplateUsed +from rdmo.questions.models import Catalog +from rdmo.questions.tests.test_models import unavailable_catalogs_kwargs from rdmo.views.models import View +from ..forms import CatalogChoiceField from ..models import Project users = ( @@ -16,6 +19,9 @@ ('user', 'user'), ('site', 'site'), ('anonymous', None), + ('editor', 'editor'), + ('reviewer', 'reviewer'), + ('api', 'api'), ) view_project_permission_map = { @@ -23,28 +29,25 @@ 'manager': [1, 3, 5, 7], 'author': [1, 3, 5, 8], 'guest': [1, 3, 5, 9], - 'api': [1, 2, 3, 4, 5], - 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + 'api': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } change_project_permission_map = { 'owner': [1, 2, 3, 4, 5, 10], 'manager': [1, 3, 5, 7], - 'api': [1, 2, 3, 4, 5], 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } delete_project_permission_map = { 'owner': [1, 2, 3, 4, 5, 10], - 'api': [1, 2, 3, 4, 5], - 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], } export_project_permission_map = { 'owner': [1, 2, 3, 4, 5, 10], 'manager': [1, 3, 5, 7], - 'api': [1, 2, 3, 4, 5], - 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + 'site': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], } projects = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -69,11 +72,10 @@ def test_list(db, client, username, password): assert response.status_code == 200 assertTemplateUsed(response, 'projects/projects.html') - if username == 'site': + if username in ('site', 'api'): assert projects == [] assert response.context['number_of_projects'] == len([]) else: - # breakpoint() user_projects_map = view_project_permission_map.get(username, []) assert sorted(list(set(map(int, projects)))) == user_projects_map assert response.context['number_of_projects'] == len(user_projects_map) @@ -113,7 +115,10 @@ def test_detail(db, client, username, password, project_id): response = client.get(url) if project_id in view_project_permission_map.get(username, []): - assert response.status_code == 200 + if username == 'api': + assert response.status_code == 403 + else: + assert response.status_code == 200 else: if password: assert response.status_code == 403 @@ -138,6 +143,38 @@ def test_project_create_get(db, client, username, password): assert response.status_code == 302 +@pytest.mark.parametrize('username,password', users) +def test_project_create_get_for_extra_users_and_unavailable_catalogs(db, client, username, password): + + for catalog_kwargs in unavailable_catalogs_kwargs: + Catalog.objects.create(**catalog_kwargs) + + client.login(username=username, password=password) + + url = reverse('project_create') + response = client.get(url) + + if password: + assert response.status_code == 200 + # check the catalogs that are displayed in the form + find_catalog_ids = re.findall(r'id="id_catalog_(\d+)', response.content.decode()) + catalogs_in_form = response.context_data['form'].fields['catalog'].queryset + # Catalog.objects.filter_availability(response.context['user']) + assert find_catalog_ids == list(map(str, range(catalogs_in_form.count()))) + + # check the unavailable catalogs that are displayed in the form + # should happen only for users that can see unavailable catalogs (editors, api,..) + for unavailable_catalog in catalogs_in_form.filter(available=False): + _label = unavailable_catalog.title + CatalogChoiceField._unavailable_icon + assert _label in response.content.decode() + + # check the parent select dropdown + for project_id in re.findall(r'