diff --git a/.circleci/config.yml b/.circleci/config.yml index d30eb272..97a7d97b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ orbs: jobs: install: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - restore_cache: @@ -33,7 +33,7 @@ jobs: - lunes_cms.egg-info compile-translations: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -56,7 +56,7 @@ jobs: - lunes_cms/locale/de/LC_MESSAGES/djangojs.mo pylint: docker: - - image: "cimg/python:3.9" + - image: "cimg/python:3.11" steps: - checkout - attach_workspace: @@ -84,7 +84,7 @@ jobs: - cc-test-reporter test: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 environment: LUNES_CMS_SECRET_KEY: circleci-dummy-key - image: cimg/postgres:14.1 @@ -137,7 +137,7 @@ jobs: ./cc-test-reporter sum-coverage -o - coverage/codeclimate.*.json | ./cc-test-reporter upload-coverage --debug --input - black: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -149,7 +149,7 @@ jobs: black --check . check-translations: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -162,7 +162,7 @@ jobs: command: ./tools/check_translations.sh build-documentation: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -172,7 +172,7 @@ jobs: command: ./tools/build_documentation.sh bump-dev-version: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -217,7 +217,7 @@ jobs: - lunes_cms/__init__.py bump-version: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -267,7 +267,7 @@ jobs: command: git checkout develop && git merge main --commit --no-edit && git push build-package: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -284,7 +284,7 @@ jobs: - dist publish-package: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: @@ -293,10 +293,10 @@ jobs: name: Publish lunes-cms package to (Test-)PyPI command: | source .venv/bin/activate - twine upload --non-interactive ./dist/lunes-cms-*.tar.gz + twine upload --non-interactive ./dist/lunes_cms-*.tar.gz create-release: docker: - - image: cimg/python:3.9 + - image: cimg/python:3.11 steps: - checkout - attach_workspace: diff --git a/.circleci/scripts/create_release.py b/.circleci/scripts/create_release.py index 5f984e66..4e3be694 100755 --- a/.circleci/scripts/create_release.py +++ b/.circleci/scripts/create_release.py @@ -34,9 +34,9 @@ def main(): logo_url = "https://raw.githubusercontent.com/digitalfabrik/lunes-cms/c242f6b723da80e5d9f9ed7ca9c6f961bb095386/.github/logo.png" compare_url = "https://github.com/digitalfabrik/lunes-cms/compare" body = ( - f"### ![]({logo_url}) lunes-cms `{args.tag}`" - f"\n\n### Changelog\n\n{args.changelog}\n\n" - f"Compare changes: [{args.prev_tag} → {args.tag}]({compare_url}/{args.prev_tag}...{args.tag})" + f"### ![]({logo_url}) lunes-cms `{args.tag}`\n\n###" + f" Changelog\n\n{args.changelog}\n\nCompare changes: [{args.prev_tag} →" + f" {args.tag}]({compare_url}/{args.prev_tag}...{args.tag})" ) # Create release diff --git a/.circleci/scripts/get_access_token.py b/.circleci/scripts/get_access_token.py index e4c5a04b..bf52f217 100755 --- a/.circleci/scripts/get_access_token.py +++ b/.circleci/scripts/get_access_token.py @@ -22,7 +22,8 @@ def main(): deliverino_private_key = os.environ["DELIVERINO_PRIVATE_KEY"] except KeyError as e: raise RuntimeError( - "Please make sure this step has access to the 'deliverino' CircleCI context." + "Please make sure this step has access to the 'deliverino' CircleCI" + " context." ) from e # Generate payload for the JWT diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b7f76fff..0f99f3cc 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ version: 2 build: os: ubuntu-20.04 tools: - python: "3.9" + python: "3.11" jobs: pre_build: - ./tools/build_documentation.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index d0a28872..79fa9d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ UNRELEASED ---------- +* [ [#512](https://github.com/digitalfabrik/lunes-cms/issues/512) ] Gender neutral language +* [ [#532](https://github.com/digitalfabrik/lunes-cms/issues/532) ] Fix color of feedback list in dark mode +* [ [#544](https://github.com/digitalfabrik/lunes-cms/issues/544) ] Refactoring of toggle_plural_field.js + 2024.6.0 -------- diff --git a/README.md b/README.md index c90a99c8..e5de84ff 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ For more information please see our [GoVolunteer ad](https://translate.google.co Following packages are required before installing the project (install them with your package manager): -* python3.8 or higher -* python3-pip -* python3-venv -* libpq-dev to compile psycopg2 -* gettext and pcregrep to use the translation features -* ffmpeg for audio processing +* `python3.11` or higher +* `python3-pip` +* `python3-venv` +* `libpq-dev` to compile psycopg2 +* `gettext` and `pcregrep` to use the translation features +* `ffmpeg` for audio processing E.g. on Debian-based distributions, use: diff --git a/docs/src/conf.py b/docs/src/conf.py index 13038acb..35b5e649 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -38,7 +38,7 @@ #: The project author author = "Lunes" #: The full version, including alpha/beta/rc tags -release = "2024.6.0" +release = "2024.11.0" #: GitHub username github_username = "digitalfabrik" #: GitHub repository name diff --git a/docs/src/installation.rst b/docs/src/installation.rst index 82162f8c..a7f8d4d1 100644 --- a/docs/src/installation.rst +++ b/docs/src/installation.rst @@ -13,7 +13,7 @@ Prerequisites Followings are required before installing the project (install them with your manager): * `git `_ -* `python3.8 `_ or higher +* `python3.11 `_ or higher * `python3-pip `_ (`Debian-based distributions `_, e.g. `Ubuntu `__) / `python-pip `_ (`Arch-based distributions `_) * `python3-venv `__ * `libpq-dev `__ to compile `psycopg2 `__ diff --git a/lunes_cms/README.md b/lunes_cms/README.md index 98aa9d2f..f1fb3825 100644 --- a/lunes_cms/README.md +++ b/lunes_cms/README.md @@ -19,7 +19,7 @@ This is the content management system for the vocabulary trainer app Lunes, whic Following packages are required before installing the project (install them with your package manager): -* python3.8 or greater +* python3.11 or greater * python3-pip * python3-venv * ffmpeg diff --git a/lunes_cms/api/exception_handler.py b/lunes_cms/api/exception_handler.py new file mode 100644 index 00000000..f8326013 --- /dev/null +++ b/lunes_cms/api/exception_handler.py @@ -0,0 +1,16 @@ +from rest_framework.views import exception_handler +from rest_framework import status + + +def custom_exception_handler(exc, context): + """ + Extend the default exception_handler of rest_framework. + Purpose: Simplify testing by ensuring that the detail message is the same for all 404 responses. + """ + + response = exception_handler(exc, context) + + if response.status_code == status.HTTP_404_NOT_FOUND: + response.data["detail"] = "Not found." + + return response diff --git a/lunes_cms/api/utils.py b/lunes_cms/api/utils.py index e48e1724..c410cf70 100644 --- a/lunes_cms/api/utils.py +++ b/lunes_cms/api/utils.py @@ -5,7 +5,7 @@ from django.core.exceptions import PermissionDenied from django.db.models import Count, Q from django.http import JsonResponse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import routers @@ -181,9 +181,11 @@ def find_duplicates_for_word(request, word): result = { "message": _("This word is already registered in the system."), "word": document_to_string(duplicate) + " (" + duplicate.word_type + ")", - "definition": _("Definition: ") + duplicate.definition - if duplicate.definition - else _("Definition: ") + _("No definition is provided for this word."), + "definition": ( + _("Definition: ") + duplicate.definition + if duplicate.definition + else _("Definition: ") + _("No definition is provided for this word.") + ), "training_sets": _("Training sets: ") + training_sets_description, } diff --git a/lunes_cms/api/v1/serializers/feedback_serializer.py b/lunes_cms/api/v1/serializers/feedback_serializer.py index a37eaf91..95015f81 100644 --- a/lunes_cms/api/v1/serializers/feedback_serializer.py +++ b/lunes_cms/api/v1/serializers/feedback_serializer.py @@ -1,6 +1,6 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from ....cms.models import Feedback @@ -19,7 +19,8 @@ class FeedbackSerializer(serializers.ModelSerializer): ), error_messages={ "does_not_exist": _( - "The content type must be either 'discipline', 'training set' or 'document'." + "The content type must be either 'discipline', 'training set' or" + " 'document'." ), }, ) diff --git a/lunes_cms/api/v1/urls.py b/lunes_cms/api/v1/urls.py index e0450fd3..51570e0f 100644 --- a/lunes_cms/api/v1/urls.py +++ b/lunes_cms/api/v1/urls.py @@ -14,7 +14,7 @@ router = OptionalSlashRouter() router.register(r"disciplines", views.DisciplineViewSet, "disciplines") router.register( - "disciplines_by_level/", + "disciplines_by_level", views.DisciplineFilteredViewSet, "disciplines_overview", ) @@ -41,7 +41,9 @@ ) router.register( - r"document_by_id/(?P[0-9]+)", views.DocumentByIdViewSet, "documents" + r"document_by_id/(?P[0-9]+)", + views.DocumentByIdViewSet, + "document_by_id", ) router.register(r"words", views.WordViewSet, "words") router.register(r"group_info", views.GroupViewSet, "group_by_id") diff --git a/lunes_cms/cms/admin.py b/lunes_cms/cms/admin.py index d7ef6468..ad00be00 100644 --- a/lunes_cms/cms/admin.py +++ b/lunes_cms/cms/admin.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, unicode_literals from django.contrib import admin -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .admins import ( DisciplineAdmin, diff --git a/lunes_cms/cms/admins/discipline_admin.py b/lunes_cms/cms/admins/discipline_admin.py index cc2f77ca..d50b4a79 100644 --- a/lunes_cms/cms/admins/discipline_admin.py +++ b/lunes_cms/cms/admins/discipline_admin.py @@ -10,7 +10,7 @@ from django.http import HttpResponse from django.urls import reverse from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from mptt.admin import DraggableMPTTAdmin from tablib import Dataset diff --git a/lunes_cms/cms/admins/document_admin.py b/lunes_cms/cms/admins/document_admin.py index 35161ae2..54ebab65 100644 --- a/lunes_cms/cms/admins/document_admin.py +++ b/lunes_cms/cms/admins/document_admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.db.models import Case, Exists, IntegerField, OuterRef, Value, When -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from ..list_filter import ( ApprovedImageListFilter, @@ -258,5 +258,5 @@ class Media: css = {"all": ("css/document_form.css",)} js = ( "js/image_preview.js", - "js/toggle_plural_field.js", + "js/toggle_document_form_fields.js", ) diff --git a/lunes_cms/cms/admins/document_resource.py b/lunes_cms/cms/admins/document_resource.py index a998e3da..847c3128 100644 --- a/lunes_cms/cms/admins/document_resource.py +++ b/lunes_cms/cms/admins/document_resource.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from import_export import fields, resources from import_export.admin import ExportActionMixin @@ -103,4 +103,13 @@ class Meta: """ model = Document - fields = () + fields = ( + "word", + "word_type", + "singular_article", + "plural_article", + "has_audio", + "example_sentence", + "creation_date", + "training_sets", + ) diff --git a/lunes_cms/cms/admins/sponsor_admin.py b/lunes_cms/cms/admins/sponsor_admin.py index 165706c7..078a94da 100644 --- a/lunes_cms/cms/admins/sponsor_admin.py +++ b/lunes_cms/cms/admins/sponsor_admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from ..utils import get_image_tag diff --git a/lunes_cms/cms/admins/training_set_admin.py b/lunes_cms/cms/admins/training_set_admin.py index 485600c1..419a39c8 100644 --- a/lunes_cms/cms/admins/training_set_admin.py +++ b/lunes_cms/cms/admins/training_set_admin.py @@ -6,7 +6,7 @@ from django.urls import reverse from django.utils.safestring import mark_safe from django.utils.translation import ngettext -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from mptt.admin import DraggableMPTTAdmin from ..forms import TrainingSetForm @@ -217,8 +217,10 @@ def make_released(self, request, queryset): messages.error( request, ngettext( - "The training set {} could not be released because it contains less than {} vocabulary words with confirmed images.", - "The training sets {} could not be released because they contain less than {} vocabulary words with confirmed images.", + "The training set {} could not be released because it contains less" + " than {} vocabulary words with confirmed images.", + "The training sets {} could not be released because they contain" + " less than {} vocabulary words with confirmed images.", len(invalid_trainingsets), ).format( iter_to_string(invalid_trainingsets), diff --git a/lunes_cms/cms/apps.py b/lunes_cms/cms/apps.py index 2275f3a5..bda3d6b3 100644 --- a/lunes_cms/cms/apps.py +++ b/lunes_cms/cms/apps.py @@ -1,5 +1,5 @@ from django.apps import AppConfig -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class CmsConfig(AppConfig): diff --git a/lunes_cms/cms/forms.py b/lunes_cms/cms/forms.py index 11a14091..e6dba5b4 100644 --- a/lunes_cms/cms/forms.py +++ b/lunes_cms/cms/forms.py @@ -2,7 +2,7 @@ from django.conf import settings from django.contrib.admin.widgets import FilteredSelectMultiple from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .models import Discipline, Document, TrainingSet from .widgets import ManyToManyOverlay @@ -52,7 +52,9 @@ class Meta: widget=ManyToManyOverlay(verbose_name=(_("vocabulary")), is_stacked=False), label=_("vocabulary"), help_text=_( - "Please select some vocabularies for your training set. To see a preview of the corresponding image and audio files, press the alt key while selecting." + "Please select some vocabularies for your training set. To see a preview of" + " the corresponding image and audio files, press the alt key while" + " selecting." ), ) @@ -74,7 +76,8 @@ def clean(self): self.add_error( "released", _( - "You can only release a training set that contains at least {} vocabulary words with confirmed images." + "You can only release a training set that contains at least {}" + " vocabulary words with confirmed images." ).format(settings.TRAININGSET_MIN_DOCS), ) return cleaned_data diff --git a/lunes_cms/cms/list_filter.py b/lunes_cms/cms/list_filter.py index 59ebbd77..ed10bd60 100644 --- a/lunes_cms/cms/list_filter.py +++ b/lunes_cms/cms/list_filter.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.db.models import F -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .models import Discipline, TrainingSet diff --git a/lunes_cms/cms/migrations/0001_initial.py b/lunes_cms/cms/migrations/0001_initial.py index 991011df..b414291d 100644 --- a/lunes_cms/cms/migrations/0001_initial.py +++ b/lunes_cms/cms/migrations/0001_initial.py @@ -242,7 +242,10 @@ class Migration(migrations.Migration): "name", models.CharField( default=None, - help_text="A free-form name for the API key. Need not be unique. 50 characters max.", + help_text=( + "A free-form name for the API key. Need not be unique. 50" + " characters max." + ), max_length=50, ), ), @@ -251,14 +254,19 @@ class Migration(migrations.Migration): models.BooleanField( blank=True, default=False, - help_text="If the API key is revoked, clients cannot use it anymore. (This cannot be undone.)", + help_text=( + "If the API key is revoked, clients cannot use it anymore." + " (This cannot be undone.)" + ), ), ), ( "expiry_date", models.DateTimeField( blank=True, - help_text="Once API key expires, clients cannot use it anymore.", + help_text=( + "Once API key expires, clients cannot use it anymore." + ), null=True, verbose_name="Expires", ), diff --git a/lunes_cms/cms/migrations/0004_feedback.py b/lunes_cms/cms/migrations/0004_feedback.py index 68ad9538..c3d10256 100644 --- a/lunes_cms/cms/migrations/0004_feedback.py +++ b/lunes_cms/cms/migrations/0004_feedback.py @@ -62,7 +62,10 @@ class Migration(migrations.Migration): "read_by", models.ForeignKey( blank=True, - help_text="The user who marked this feedback as read. If the feedback is unread, this field is empty.", + help_text=( + "The user who marked this feedback as read. If the feedback" + " is unread, this field is empty." + ), null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="feedback", diff --git a/lunes_cms/cms/migrations/0006_convert_group_api_key.py b/lunes_cms/cms/migrations/0006_convert_group_api_key.py index 73a9fca9..84c576df 100644 --- a/lunes_cms/cms/migrations/0006_convert_group_api_key.py +++ b/lunes_cms/cms/migrations/0006_convert_group_api_key.py @@ -60,7 +60,9 @@ class Migration(migrations.Migration): name="token", field=models.CharField( default=lunes_cms.cms.models.group_api_key.generate_default_token, - help_text="10-50 characters, only digits and upper case letters allowed.", + help_text=( + "10-50 characters, only digits and upper case letters allowed." + ), max_length=50, unique=True, validators=[ diff --git a/lunes_cms/cms/models/alternative_word.py b/lunes_cms/cms/models/alternative_word.py index 323ce7c2..155434c6 100644 --- a/lunes_cms/cms/models/alternative_word.py +++ b/lunes_cms/cms/models/alternative_word.py @@ -1,5 +1,5 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .document import Document from .static import Static diff --git a/lunes_cms/cms/models/discipline.py b/lunes_cms/cms/models/discipline.py index 3b8349aa..94b546e2 100644 --- a/lunes_cms/cms/models/discipline.py +++ b/lunes_cms/cms/models/discipline.py @@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.db.models.deletion import CASCADE -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from mptt.models import MPTTModel, TreeForeignKey from ..utils import get_child_count, get_image_tag diff --git a/lunes_cms/cms/models/document.py b/lunes_cms/cms/models/document.py index ead06a6b..c1f5f5b4 100644 --- a/lunes_cms/cms/models/document.py +++ b/lunes_cms/cms/models/document.py @@ -4,7 +4,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.core.files import File from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from pydub import AudioSegment from ..utils import document_to_string diff --git a/lunes_cms/cms/models/document_image.py b/lunes_cms/cms/models/document_image.py index 78414065..7cddcaee 100644 --- a/lunes_cms/cms/models/document_image.py +++ b/lunes_cms/cms/models/document_image.py @@ -1,5 +1,5 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from PIL import Image, ImageFilter from ..utils import get_image_tag @@ -44,6 +44,7 @@ def save_original_img(self): :rtype: None """ name_elements = self.image.path.split(".") + new_path = "" for elem in name_elements: if elem != name_elements[-1]: new_path = elem + "_" diff --git a/lunes_cms/cms/models/feedback.py b/lunes_cms/cms/models/feedback.py index 315b97a5..2c4c3675 100644 --- a/lunes_cms/cms/models/feedback.py +++ b/lunes_cms/cms/models/feedback.py @@ -43,7 +43,8 @@ class Feedback(models.Model): related_name="feedback", verbose_name=_("marked as read by"), help_text=_( - "The user who marked this feedback as read. If the feedback is unread, this field is empty." + "The user who marked this feedback as read. If the feedback is unread, this" + " field is empty." ), ) diff --git a/lunes_cms/cms/models/group.py b/lunes_cms/cms/models/group.py index dee718f6..c161aec3 100644 --- a/lunes_cms/cms/models/group.py +++ b/lunes_cms/cms/models/group.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import Group from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .static import convert_umlaute_images diff --git a/lunes_cms/cms/models/group_api_key.py b/lunes_cms/cms/models/group_api_key.py index 7dc5a42a..eb3189db 100644 --- a/lunes_cms/cms/models/group_api_key.py +++ b/lunes_cms/cms/models/group_api_key.py @@ -9,7 +9,7 @@ from django.utils.crypto import get_random_string from django.utils.html import mark_safe from django.utils.timezone import now -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from qr_code.qrcode.maker import make_qr_code_url_with_args @@ -99,7 +99,8 @@ def qr_code_link(self, link, title=None): :rtype: str """ return mark_safe( - f'{link}' + f'{link}' ) def qr_code_download_link(self): @@ -119,7 +120,8 @@ def qr_code(self): return ( self.qr_code_link( mark_safe( - f'' + f'" ), escape(_("Download QR code")), ) diff --git a/lunes_cms/cms/models/sponsor.py b/lunes_cms/cms/models/sponsor.py index 75940b5d..6a79ec13 100644 --- a/lunes_cms/cms/models/sponsor.py +++ b/lunes_cms/cms/models/sponsor.py @@ -1,5 +1,5 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from ..validators import validate_multiple_extensions from .static import upload_sponsor_logos diff --git a/lunes_cms/cms/models/training_set.py b/lunes_cms/cms/models/training_set.py index 9f2c5ad1..8bb0a4ca 100644 --- a/lunes_cms/cms/models/training_set.py +++ b/lunes_cms/cms/models/training_set.py @@ -4,7 +4,7 @@ from django.db import models from django.db.models.deletion import CASCADE from django.utils.html import format_html -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from mptt.models import MPTTModel, TreeForeignKey from ..utils import get_image_tag @@ -76,7 +76,8 @@ def save(self, *args, **kwargs): """ if self.parent: msg = _( - "It is not possible to create child elements for training sets (unlike disciplines)." + "It is not possible to create child elements for training sets (unlike" + " disciplines)." ) raise ValidationError(msg) super().save(*args, **kwargs) diff --git a/lunes_cms/cms/urls.py b/lunes_cms/cms/urls.py index 013e6ac8..df38ba47 100644 --- a/lunes_cms/cms/urls.py +++ b/lunes_cms/cms/urls.py @@ -7,7 +7,7 @@ from django.contrib import admin from django.contrib.auth import views as auth_views from django.urls import path -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.i18n import JavaScriptCatalog #: The url patterns of this module (see :doc:`django:topics/http/urls`) diff --git a/lunes_cms/cms/utils.py b/lunes_cms/cms/utils.py index 59700596..0a25357e 100644 --- a/lunes_cms/cms/utils.py +++ b/lunes_cms/cms/utils.py @@ -10,7 +10,7 @@ from django.utils.crypto import get_random_string from django.utils.html import mark_safe -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ def create_resource_path(parent_dir, filename): @@ -61,7 +61,7 @@ def document_to_string(doc): :rtype: str """ alt_words = [str(elem) for elem in doc.alternatives.all()] - has_foto = "\U0001F4F7" if doc.document_image.all() else "\U000026A0" + has_foto = "\U0001f4f7" if doc.document_image.all() else "\U000026a0" if len(alt_words) > 0: alt_words = "(" + ", ".join(alt_words) + ")" diff --git a/lunes_cms/cms/validators.py b/lunes_cms/cms/validators.py index d8dd81fc..943d25ed 100644 --- a/lunes_cms/cms/validators.py +++ b/lunes_cms/cms/validators.py @@ -1,7 +1,7 @@ import os from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ def validate_file_extension(value): diff --git a/lunes_cms/core/settings.py b/lunes_cms/core/settings.py index 0602a83f..04638912 100644 --- a/lunes_cms/core/settings.py +++ b/lunes_cms/core/settings.py @@ -12,12 +12,11 @@ import os -from distutils.util import strtobool - from django.core.exceptions import ImproperlyConfigured -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .logging_formatter import ColorFormatter +from .utils import strtobool ################### # CUSTOM SETTINGS # @@ -137,7 +136,8 @@ } except KeyError as e: raise ImproperlyConfigured( - f"The database backend {os.environ.get('LUNES_CMS_DB_BACKEND')!r} is not supported, must be one of {DATABASE_CHOICES.keys()}." + f"The database backend {os.environ.get('LUNES_CMS_DB_BACKEND')!r} is not" + f" supported, must be one of {DATABASE_CHOICES.keys()}." ) from e #: Default primary key field type to use for models that don’t have a field with primary_key=True. @@ -171,7 +171,9 @@ #: See Password validation for more details. By default, no validation is performed and all passwords are accepted. AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "NAME": ( + "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + ), }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", @@ -333,7 +335,10 @@ "style": "{", }, "email": { - "format": "Date and time: {asctime}\nSeverity: {levelname}\nLogger: {name}\nMessage: {message}\nFile: {funcName}() in {pathname}:{lineno}", + "format": ( + "Date and time: {asctime}\nSeverity: {levelname}\nLogger:" + " {name}\nMessage: {message}\nFile: {funcName}() in {pathname}:{lineno}" + ), "datefmt": "%Y-%m-%d %H:%M:%S", "style": "{", }, @@ -416,6 +421,7 @@ "ALLOWED_VERSIONS": ("v1", "v2"), "DEFAULT_VERSION": "default", "DEFAULT_API_URL": "http://localhost:8080/api/", + "EXCEPTION_HANDLER": "lunes_cms.api.exception_handler.custom_exception_handler", } SPECTACULAR_SETTINGS = { diff --git a/lunes_cms/core/urls.py b/lunes_cms/core/urls.py index 059783da..787e636d 100644 --- a/lunes_cms/core/urls.py +++ b/lunes_cms/core/urls.py @@ -20,12 +20,10 @@ """ from django.conf import settings -from django.conf.urls import url from django.conf.urls.i18n import i18n_patterns from django.conf.urls.static import static from django.templatetags.static import static as get_static_url -from django.urls import include, path, reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.urls import include, path, re_path, reverse_lazy from django.views.generic.base import RedirectView #: The url patterns of this module (see :doc:`django:topics/http/urls`) @@ -37,7 +35,7 @@ ), path("api/", include("lunes_cms.api.urls", namespace="api")), path("", include("lunes_cms.help.urls")), - url(r"^i18n/", include("django.conf.urls.i18n")), + re_path(r"^i18n/", include("django.conf.urls.i18n")), path("qr_code/", include("qr_code.urls", namespace="qr_code")), ] diff --git a/lunes_cms/core/utils.py b/lunes_cms/core/utils.py new file mode 100644 index 00000000..ac605631 --- /dev/null +++ b/lunes_cms/core/utils.py @@ -0,0 +1,13 @@ +def strtobool(val): + """Convert a string representation of truth to true (1) or false (0). + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + """ + val = val.lower() + if val in ("y", "yes", "t", "true", "on", "1"): + return 1 + if val in ("n", "no", "f", "false", "off", "0"): + return 0 + raise ValueError(f"invalid truth value {val}") diff --git a/lunes_cms/locale/de/LC_MESSAGES/django.po b/lunes_cms/locale/de/LC_MESSAGES/django.po index 75d29862..c201300e 100644 --- a/lunes_cms/locale/de/LC_MESSAGES/django.po +++ b/lunes_cms/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-19 14:40+0000\n" +"POT-Creation-Date: 2024-10-27 22:23+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -29,19 +29,19 @@ msgstr "Das word ist zu keinem Modul zugeordnet." msgid "This word is already registered in the system." msgstr "Das Wort ist schon im System hinterlegt." -#: api/utils.py:184 api/utils.py:186 +#: api/utils.py:185 api/utils.py:187 msgid "Definition: " msgstr "Definition: " -#: api/utils.py:186 +#: api/utils.py:187 msgid "No definition is provided for this word." msgstr "Für dieses Wort ist keine Definition hinterlegt." -#: api/utils.py:187 +#: api/utils.py:189 msgid "Training sets: " msgstr "Module: " -#: api/utils.py:191 +#: api/utils.py:193 msgid "This word is not yet registered in the system" msgstr "Das Wort ist noch nicht im System hinterlegt." @@ -52,17 +52,17 @@ msgstr "" "Der Inhaltstyp muss entweder 'discipline', 'trainingset' oder 'document' " "sein." -#: api/v1/serializers/feedback_serializer.py:35 +#: api/v1/serializers/feedback_serializer.py:36 msgid "{} with id {} does not exist." msgstr "{} mit der ID {} existiert nicht." #: cms/admin.py:35 cms/admins/document_admin.py:162 -#: cms/admins/training_set_admin.py:359 cms/forms.py:46 cms/forms.py:48 +#: cms/admins/training_set_admin.py:361 cms/forms.py:46 cms/forms.py:48 #: cms/list_filter.py:14 cms/models/discipline.py:101 msgid "disciplines" msgstr "Modulgruppen" -#: cms/admin.py:36 cms/list_filter.py:103 cms/models/training_set.py:91 +#: cms/admin.py:36 cms/list_filter.py:103 cms/models/training_set.py:92 msgid "training sets" msgstr "Module" @@ -75,7 +75,7 @@ msgstr "Vokabeln" msgid "api keys" msgstr "API Keys" -#: cms/admin.py:39 cms/models/feedback.py:89 +#: cms/admin.py:39 cms/models/feedback.py:90 msgid "feedback" msgstr "Feedback" @@ -104,12 +104,12 @@ msgid "published words in released modules" msgstr "veröffentlichte Vokabeln in veröffentlichten Modulen" #: cms/admins/discipline_admin.py:387 cms/admins/document_admin.py:179 -#: cms/admins/training_set_admin.py:376 +#: cms/admins/training_set_admin.py:378 msgid "creator group" msgstr "Besitzergruppe" #: cms/admins/document_admin.py:142 cms/models/training_set.py:25 -#: cms/models/training_set.py:90 +#: cms/models/training_set.py:91 msgid "training set" msgstr "Modul" @@ -117,7 +117,7 @@ msgstr "Modul" msgid "audio" msgstr "Audio" -#: cms/admins/document_admin.py:216 cms/models/document_image.py:123 +#: cms/admins/document_admin.py:216 cms/models/document_image.py:124 msgid "image" msgstr "Bild" @@ -206,43 +206,43 @@ msgstr[1] "" "Die Module {} konnten nicht veröffentlicht werden, da sie weniger als {} " "Vokabeln mit bestätigten Bildern enthalten." -#: cms/admins/training_set_admin.py:233 +#: cms/admins/training_set_admin.py:235 msgid "The training set {} is already released." msgid_plural "The training sets {} are already released." msgstr[0] "Das Modul {} ist bereits veröffentlicht." msgstr[1] "Die Module {} sind bereits veröffentlicht." -#: cms/admins/training_set_admin.py:247 +#: cms/admins/training_set_admin.py:249 msgid "The training set {} was successfully released." msgid_plural "The training sets {} were successfully released." msgstr[0] "Das Modul {} wurde erfolgreich veröffentlicht." msgstr[1] "Die Module {} wurden erfolgreich veröffentlicht." -#: cms/admins/training_set_admin.py:253 +#: cms/admins/training_set_admin.py:255 msgid "Unrelease selected training sets" msgstr "Ausgewählte Module zurückhalten" -#: cms/admins/training_set_admin.py:277 +#: cms/admins/training_set_admin.py:279 msgid "The training set {} is already unreleased." msgid_plural "The training sets {} are already unreleased." msgstr[0] "Das Modul {} ist bereits zurückgehalten." msgstr[1] "Die Module {} sind bereits zurückgehalten." -#: cms/admins/training_set_admin.py:288 +#: cms/admins/training_set_admin.py:290 msgid "The training set {} was successfully unreleased." msgid_plural "The training sets {} were successfully unreleased." msgstr[0] "Das Modul {} wurde erfolgreich zurückgehalten." msgstr[1] "Die Module {} wurden erfolgreich zurückgehalten." -#: cms/admins/training_set_admin.py:295 +#: cms/admins/training_set_admin.py:297 msgid "words" msgstr "Vokabeln" -#: cms/admins/training_set_admin.py:313 +#: cms/admins/training_set_admin.py:315 msgid "published words" msgstr "veröffentlichte Vokabeln" -#: cms/admins/training_set_admin.py:331 +#: cms/admins/training_set_admin.py:333 msgid "unpublished words" msgstr "unveröffentlichte Vokabeln" @@ -259,7 +259,7 @@ msgstr "" "Bilder und Audio-Dateien zu sehen, drücke die Alt-Taste, während du ein " "Element auswählst." -#: cms/forms.py:77 +#: cms/forms.py:79 msgid "" "You can only release a training set that contains at least {} vocabulary " "words with confirmed images." @@ -395,7 +395,7 @@ msgstr "Zusätzliche Bedeutung 1" msgid "additional meaning 2" msgstr "Zusätzliche Bedeutung 2" -#: cms/models/document_image.py:124 +#: cms/models/document_image.py:125 msgid "images" msgstr "Bilder" @@ -415,7 +415,7 @@ msgstr "Objekt-ID" msgid "The id of the object this feedback entry refers to." msgstr "Die ID des Objekts, auf das sich dieser Feedback-Eintrag bezieht." -#: cms/models/feedback.py:32 cms/models/feedback.py:72 +#: cms/models/feedback.py:32 cms/models/feedback.py:73 msgid "refers to" msgstr "bezieht sich auf" @@ -432,18 +432,18 @@ msgid "" "The user who marked this feedback as read. If the feedback is unread, this " "field is empty." msgstr "" -"Der Benutzer, der dieses Feedback als gelesen markiert hat. Wenn das " +"Die nutzende Person, die dieses Feedback als gelesen markiert hat. Wenn das " "Feedback ungelesen ist, ist dieses Feld leer." -#: cms/models/feedback.py:52 +#: cms/models/feedback.py:53 msgid "submitted on" msgstr "übermittelt am" -#: cms/models/feedback.py:53 +#: cms/models/feedback.py:54 msgid "The time and date when the feedback was submitted." msgstr "Uhrzeit und Datum, an dem das Feedback eingereicht wurde." -#: cms/models/feedback.py:91 +#: cms/models/feedback.py:92 msgid "feedback entries" msgstr "Feedback-Einträge" @@ -487,27 +487,27 @@ msgstr "" msgid "valid" msgstr "gültig" -#: cms/models/group_api_key.py:110 +#: cms/models/group_api_key.py:111 msgid "Download" msgstr "Herunterladen" -#: cms/models/group_api_key.py:112 cms/models/group_api_key.py:130 +#: cms/models/group_api_key.py:113 cms/models/group_api_key.py:132 msgid "QR code" msgstr "QR-Code" -#: cms/models/group_api_key.py:124 +#: cms/models/group_api_key.py:126 msgid "Download QR code" msgstr "QR-Code herunterladen" -#: cms/models/group_api_key.py:156 +#: cms/models/group_api_key.py:158 msgid "{}: Token for the group \"{}\"" msgstr "{}: Token für die Gruppe \"{}\"" -#: cms/models/group_api_key.py:163 +#: cms/models/group_api_key.py:165 msgid "API Key" msgstr "API-Key" -#: cms/models/group_api_key.py:164 +#: cms/models/group_api_key.py:166 msgid "API Keys" msgstr "API-Keys" @@ -521,11 +521,11 @@ msgstr "URL" #: cms/models/sponsor.py:43 msgid "sponsor" -msgstr "Sponsor" +msgstr "Sponsor:in" #: cms/models/sponsor.py:44 msgid "sponsors" -msgstr "Sponsoren" +msgstr "Sponsor:innen" #: cms/models/training_set.py:33 msgid "document" @@ -639,19 +639,19 @@ msgstr "Datei zu groß! Max. 5 MB" msgid "Only use one file extension!" msgstr "Nur maximal ein Dateityp erlaubt!" -#: core/settings.py:204 +#: core/settings.py:206 msgid "English" msgstr "Englisch" -#: core/settings.py:205 +#: core/settings.py:207 msgid "German" msgstr "Deutsch" -#: core/settings.py:445 core/settings.py:446 core/settings.py:448 +#: core/settings.py:451 core/settings.py:452 core/settings.py:454 msgid "Lunes Administration" msgstr "Lunes-Verwaltung" -#: core/settings.py:447 +#: core/settings.py:453 msgid "Welcome to the vocabulary management of Lunes!" msgstr "Willkommen bei der Vokabelverwaltung von Lunes!" diff --git a/lunes_cms/static/css/feedback.css b/lunes_cms/static/css/feedback.css index a070e35b..4df69f7b 100644 --- a/lunes_cms/static/css/feedback.css +++ b/lunes_cms/static/css/feedback.css @@ -22,6 +22,28 @@ thead tr { font-weight: bold; } +@media (prefers-color-scheme: dark) { + + .table-striped tbody tr:nth-of-type(odd){ + background-color: #000e38; + + } + + .table-striped thead tr { + background-color: #47476e; + font-weight: bold; + } + + thead th .text { + color: #8ba6fa; + } + + tbody { + color: #8ba6fa; + } + +} + /* Checkbox column */ thead th:nth-child(1) { width: 3%; diff --git a/lunes_cms/static/js/toggle_document_form_fields.js b/lunes_cms/static/js/toggle_document_form_fields.js new file mode 100644 index 00000000..c7cc655b --- /dev/null +++ b/lunes_cms/static/js/toggle_document_form_fields.js @@ -0,0 +1,103 @@ +if (!$) { + $ = django.jQuery; +} + +// Toggle the plural field depending on the chosen word type +$(document).ready(() => { + const togglePluralWordInput = () => { + const isNoun = $("#id_word_type").val() === "Nomen"; + $("#id_plural").closest("div.row").toggle(isNoun); + }; + + $("#id_word_type").change(togglePluralWordInput); + togglePluralWordInput(); +}); + +// Toggle the drop down for grammatical gender depending on the chosen word type +$(document).ready(() => { + const toggleGenderDropdown = () => { + const isNoun = $("#id_word_type").val() === "Nomen"; + $("#id_grammatical_gender").closest("div.row").toggle(isNoun); + }; + + $("#id_word_type").change(toggleGenderDropdown); + toggleGenderDropdown(); +}); + + +// Detect changes in the "word" field and search for a duplicate +$(document).ready(() => { + $("#id_word").change((event) => { + if ($(event.target).val().length > 0) { + $.ajax({ + type: 'GET', + url: '/api/search_duplicate/' + $(event.target).val(), + dataType: "json", + success: function(data) { + showDuplicates(data, $(event.target).closest(".card-body")); + } + }) + } else { + removeDuplicationCheckMessage(); + } + }); + $("#id_word_type").trigger("change"); +}); + +// Create and show message whether there is a possible duplicate +function showDuplicates(data, parent) { + removeDuplicationCheckMessage(); + + if (data["word"]) { + // If there is a duplicated word, use orange background + result = createSearchResultField("#ffbb4a"); + + // Show alert message + addDetailInfo(result, data["message"], "normal"); + + // Show the duplicated word with its word type + addDetailInfo(result, data["word"], "bold"); + + // Show its definition too for more detail + addDetailInfo(result, data["definition"], "normal"); + + // Show related training sets + addDetailInfo(result, data["training_sets"], "normal"); + } else { + // If there is no duplicate, use green background + result = createSearchResultField("#72f399"); + + // Show message that no duplicate was found + addDetailInfo(result, data["message"], "normal"); + } + + parent.prepend(result); +} + +// Create a zone in which result duplicate search will be shown +function createSearchResultField(backgroundColor){ + messageField = document.createElement("div"); + messageField.setAttribute("id", "result"); + messageField.style.padding = "25px"; + messageField.style.backgroundColor = backgroundColor; + + return messageField; +} + +// Create and add detail information +function addDetailInfo(resultField, info, fontWeight) { + detailInfoField = document.createElement("div"); + detailInfoField.style.fontWeight = fontWeight; + detailInfo = document.createTextNode(info); + detailInfoField.append(detailInfo); + resultField.append(detailInfoField); +} + +// Remove the duplicate search result +function removeDuplicationCheckMessage(){ + const existingMessage = document.getElementById("result"); + + if (existingMessage) { + existingMessage.remove(); + } +} diff --git a/lunes_cms/static/js/toggle_plural_field.js b/lunes_cms/static/js/toggle_plural_field.js deleted file mode 100644 index cb110a57..00000000 --- a/lunes_cms/static/js/toggle_plural_field.js +++ /dev/null @@ -1,97 +0,0 @@ -if (!$) { - $ = django.jQuery; -} - -//Toggle the plural field depending on the chosen word type -$(document).ready(() => { - $("#id_word_type").change((event) => - $("#id_plural") - .closest("div.row") - .toggle($(event.target).val() == "Nomen"), - ); - $("#id_word_type").trigger("change"); -}); - -//Toggle the drop down for grammatical gender depending on the chosen word type -$(document).ready(() => { - $("#id_word_type").change((event) => - $("#id_grammatical_gender") - .closest("div.row") - .toggle($(event.target).val() == "Nomen"), - ); - $("#id_word_type").trigger("change"); -}); - -function removeDuplicationCheckMessage(){ - var existingMessage = document.getElementById("result"); - - if (existingMessage) { - existingMessage.remove(); - } -} - -function showDuplicates(data, parent) { - removeDuplicationCheckMessage(); - - result = document.createElement("div"); - result.setAttribute("id", "result"); - - - if (data["word"]) { - // If there is a duplicated word, use orange background - result.style.backgroundColor = "#ffbb4a"; - result.style.padding = "25px" - - // Show alert message - messageBox = document.createElement("div"); - message = document.createTextNode(data["message"]); - messageBox.append(message); - result.append(messageBox); - // Show the duplicated word with its word type - wordBox = document.createElement("div"); - word = document.createTextNode(data["word"]); - wordBox.style.fontWeight = "bold"; - wordBox.append(word); - result.append(wordBox); - // Show its definition too for more detail - definitionBox = document.createElement("div"); - definition = document.createTextNode(data["definition"]); - definitionBox.append(definition); - result.append(definitionBox); - // Show related training sets - trainingSetsBox = document.createElement("div"); - trainingSets = document.createTextNode(data["training_sets"]); - trainingSetsBox.append(trainingSets); - result.append(trainingSetsBox); - } else { - // If there is no duplicate, use green background - result.style.backgroundColor = "#72f399"; - result.style.padding = "25px" - // Show message that no duplicate was found - messageBox = document.createElement("div"); - message = document.createTextNode(data["message"]); - messageBox.append(message); - result.append(messageBox); - } - - parent.prepend(result); -} - - -$(document).ready(() => { - $("#id_word").change((event) => { - if ($(event.target).val().length > 0) { - $.ajax({ - type: 'GET', - url: '/api/search_duplicate/' + $(event.target).val(), - dataType: "json", - success: function(data) { - showDuplicates(data, $(event.target).closest(".card-body")); - } - }) - } else { - removeDuplicationCheckMessage(); - } - }); - $("#id_word_type").trigger("change"); -}); \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 867a331f..7034cfac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = lunes-cms -version = 2024.6.0 +version = 2024.11.0 author = Tür an Tür – Digitalfabrik gGmbH author_email = tech@integreat-app.de description = Content Management System for the Lunes Vocabulary Trainer App @@ -21,11 +21,10 @@ classifiers = License :: OSI Approved :: Apache Software License Operating System :: OS Independent Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 Framework :: Django - Framework :: Django :: 3.2 + Framework :: Django :: 5.1 Operating System :: POSIX :: Linux Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System Topic :: Internet :: WWW/HTTP :: WSGI :: Application @@ -45,16 +44,16 @@ keywords = packages = lunes_cms install_requires = - django==3.2.21 - django-import-export==3.3.7 - django-jazzmin==2.6.0 - django-mptt==0.15.0 - django-qr-code==3.1.1 - djangorestframework==3.14.0 - drf-spectacular==0.26.5 - ipython==8.16.0 - pillow==10.0.1 - psycopg2==2.9.8 + django==5.1.2 + django-import-export==4.2.0 + django-jazzmin==3.0.1 + django-mptt==0.16.0 + django-qr-code==4.1.0 + djangorestframework==3.15.2 + drf-spectacular==0.27.2 + ipython==8.29.0 + pillow==11.0.0 + psycopg2==2.9.10 pydub==0.25.1 python_requires = >=3.8 include_package_data = True @@ -63,24 +62,24 @@ scripts = lunes_cms/lunes-cms-cli [options.extras_require] dev = black==23.9.1 - bumpver==2023.1126 - pre-commit==3.4.0 - pyjwt==2.8.0 - pylint-django==2.5.3 - pylint-runner==0.6.0 - shellcheck-py==0.9.0.6 - twine==4.0.2 + bumpver==2023.1129 + pre-commit==4.0.1 + pyjwt==2.9.0 + pylint-django==2.6.1 + pylint-runner==0.7.0 + shellcheck-py==0.10.0.1 + twine==5.1.1 doc = - sphinx==7.2.6 - sphinx-rtd-theme==1.3.0 - sphinx-last-updated-by-git==0.3.6 + sphinx==8.1.3 + sphinx-rtd-theme==3.0.1 + sphinx-last-updated-by-git==0.3.8 sphinxcontrib-django==2.5 test = pytest-circleci-parallelized==0.1.0 - pytest-cov==4.1.0 - pytest-django==4.5.2 - pytest-icdiff==0.8 - pytest-xdist==3.3.1 + pytest-cov==5.0.0 + pytest-django==4.9.0 + pytest-icdiff==0.9 + pytest-xdist==3.6.1 [bumpver] current_version = 2024.6.0 diff --git a/tests/api/api_config.py b/tests/api/api_config.py index d6309444..f69ece48 100644 --- a/tests/api/api_config.py +++ b/tests/api/api_config.py @@ -169,22 +169,30 @@ }, { "endpoint": "/api/training_set/15/", - "expected_result": "tests/api/expected-results/training_sets_by_discipline_15.json", + "expected_result": ( + "tests/api/expected-results/training_sets_by_discipline_15.json" + ), }, { "endpoint": "/api/training_set/15/", "api_key": "VALIDTOKEN", - "expected_result": "tests/api/expected-results/training_sets_by_discipline_15.json", + "expected_result": ( + "tests/api/expected-results/training_sets_by_discipline_15.json" + ), }, { "endpoint": "/api/training_set/15/", "api_key": "INVALIDTOKEN", - "expected_result": "tests/api/expected-results/training_sets_by_discipline_15.json", + "expected_result": ( + "tests/api/expected-results/training_sets_by_discipline_15.json" + ), }, { "endpoint": "/api/training_set/20/", "api_key": "VALIDTOKEN", - "expected_result": "tests/api/expected-results/training_sets_by_discipline_20.json", + "expected_result": ( + "tests/api/expected-results/training_sets_by_discipline_20.json" + ), }, { "endpoint": "/api/training_set/20/", @@ -203,22 +211,30 @@ VOCABULARY_ENDPOINTS = [ { "endpoint": "/api/documents/7/", - "expected_result": "tests/api/expected-results/documents_by_training_set_7.json", + "expected_result": ( + "tests/api/expected-results/documents_by_training_set_7.json" + ), }, { "endpoint": "/api/documents/7/", "api_key": "VALIDTOKEN", - "expected_result": "tests/api/expected-results/documents_by_training_set_7.json", + "expected_result": ( + "tests/api/expected-results/documents_by_training_set_7.json" + ), }, { "endpoint": "/api/documents/7/", "api_key": "INVALIDTOKEN", - "expected_result": "tests/api/expected-results/documents_by_training_set_7.json", + "expected_result": ( + "tests/api/expected-results/documents_by_training_set_7.json" + ), }, { "endpoint": "/api/documents/108/", "api_key": "VALIDTOKEN", - "expected_result": "tests/api/expected-results/documents_by_training_set_108.json", + "expected_result": ( + "tests/api/expected-results/documents_by_training_set_108.json" + ), }, { "endpoint": "/api/documents/108/", @@ -351,7 +367,9 @@ { "endpoint": "/api/feedback/", "post_data": {"comment": "invalid", "content_type": "invalid", "object_id": 1}, - "expected_result": "tests/api/expected-results/feedback_invalid_content_type.json", + "expected_result": ( + "tests/api/expected-results/feedback_invalid_content_type.json" + ), "expected_status_code": 400, }, { @@ -361,7 +379,9 @@ "content_type": "document", "object_id": 1, }, - "expected_result": "tests/api/expected-results/feedback_document_not_found.json", + "expected_result": ( + "tests/api/expected-results/feedback_document_not_found.json" + ), "expected_status_code": 400, }, ] diff --git a/tools/install.sh b/tools/install.sh index cacd989a..633fbd71 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -10,7 +10,7 @@ echo "Checking system requirements..." | print_info # Check if requirements are satisfied # Define the required python version -required_python_version="8" +required_python_version="11" if [[ ! -x "$(command -v python3)" ]]; then echo "Python3 is not installed. Please install version 3.${required_python_version} or later manually and run this script again." | print_error exit 1 fi