Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ UNRELEASED
* [ [#353](https://github.com/digitalfabrik/lunes-cms/issues/353) ] Filter feedback by creator of related objects
* [ [#468](https://github.com/digitalfabrik/lunes-cms/issues/468) ] Excel list out of existing vocabulary in cms
* [ [#534](https://github.com/digitalfabrik/lunes-cms/issues/534) ] Adjust form appearance for small screens
* [ [#470](https://github.com/digitalfabrik/lunes-cms/issues/470) ] Inform users of word duplication in document form


2024.5.1
Expand Down
42 changes: 40 additions & 2 deletions lunes_cms/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

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 rest_framework import routers

from ..cms.models import Discipline, GroupAPIKey
from ..cms.utils import get_child_count
from ..cms.models import Discipline, GroupAPIKey, Document
from ..cms.utils import get_child_count, document_to_string


class OptionalSlashRouter(routers.DefaultRouter):
Expand Down Expand Up @@ -151,3 +154,38 @@ def check_group_object_permissions(request, group_id):
api_key_object = GroupAPIKey.get_from_token(key)
if api_key_object.group_id != int(group_id):
raise PermissionDenied()


def find_duplicates_for_word(request, word):
"""
Function to find existing words that match the input in the "word" field of document

:param request: current request
:type request: HttpRequest

:param group_id: input in the "word"field of document
:type group_id: str

:return: Whether any duplicate was found, and some details of the word if found
:rtype: JsonResponse

"""

if duplicate := Document.objects.filter(word=word).first():
training_sets_description = _("This word is assigned to no training set.")
if training_sets := duplicate.training_sets.all():
training_sets_description = ", ".join(
str(training_set) for training_set in training_sets
)

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."),
"training_sets": _("Training sets: ") + training_sets_description,
}

return JsonResponse(result)
return JsonResponse({"message": _("This word is not yet registered in the system")})
7 changes: 6 additions & 1 deletion lunes_cms/api/v1/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.urls import include, path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

from ..utils import OptionalSlashRouter
from ..utils import OptionalSlashRouter, find_duplicates_for_word
from . import views

#: The namespace for this URL config (see :attr:`django.urls.ResolverMatch.app_name`)
Expand Down Expand Up @@ -59,4 +59,9 @@
),
name="swagger-ui",
),
path(
"search_duplicate/<word>",
find_duplicates_for_word,
name="search_duplicate",
),
]
15 changes: 15 additions & 0 deletions lunes_cms/cms/fixtures/test_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -6891,6 +6891,7 @@
"word_type": "Nomen",
"word": "Ei",
"singular_article": 3,
"definition": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua",
Comment thread
MizukiTemma marked this conversation as resolved.
"audio": "audio/ei.mp3",
"creation_date": "2021-08-09T13:52:38.131Z",
"created_by": null,
Expand Down Expand Up @@ -13411,6 +13412,20 @@
"creator_is_admin": true
}
},
{
"model": "cms.document",
"pk": 2332,
"fields": {
"word_type": "Verb",
"word": "implementieren",
"singular_article": 0,
"definition": "in ein bestehendes Computersystem einsetzen, einbauen und so ein funktionsfähiges Programm erstellen",
"example_sentence": "eine neue Software implementieren",
"creation_date": "2021-04-13T15:58:10.468Z",
"created_by": null,
"creator_is_admin": true
}
},
{
"model": "cms.alternativeword",
"pk": 1,
Expand Down
26 changes: 25 additions & 1 deletion lunes_cms/locale/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-11 15:29+0000\n"
"POT-Creation-Date: 2024-06-19 14:40+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -21,6 +21,30 @@ msgstr ""
msgid "API"
msgstr "API"

#: api/utils.py:175
msgid "This word is assigned to no training set."
msgstr "Das word ist zu keinem Modul zugeordnet."

#: api/utils.py:182
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
msgid "Definition: "
msgstr "Definition: "

#: api/utils.py:186
msgid "No definition is provided for this word."
msgstr "Für dieses Wort ist keine Definition hinterlegt."

#: api/utils.py:187
msgid "Training sets: "
msgstr "Module: "

#: api/utils.py:191
msgid "This word is not yet registered in the system"
msgstr "Das Wort ist noch nicht im System hinterlegt."

#: api/v1/serializers/feedback_serializer.py:22
msgid ""
"The content type must be either 'discipline', 'training set' or 'document'."
Expand Down
76 changes: 76 additions & 0 deletions lunes_cms/static/js/toggle_plural_field.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ if (!$) {
$ = django.jQuery;
}

//Toggle the plural field depending on the chosen word type
$(document).ready(() => {
$("#id_word_type").change((event) =>
$("#id_plural")
Expand All @@ -11,6 +12,7 @@ $(document).ready(() => {
$("#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")
Expand All @@ -19,3 +21,77 @@ $(document).ready(() => {
);
$("#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");
});
21 changes: 21 additions & 0 deletions tests/api/api_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,26 @@
},
]


SEARCH_DUPLICATE_ENDPOINTS = [
{
"endpoint": "/api/search_duplicate/implementieren",
"expected_result": "tests/api/expected-results/duplicate_implementieren.json",
},
{
"endpoint": "/api/search_duplicate/Schere",
"expected_result": "tests/api/expected-results/duplicate_Schere.json",
},
{
"endpoint": "/api/search_duplicate/Ei",
"expected_result": "tests/api/expected-results/duplicate_Ei.json",
},
{
"endpoint": "/api/search_duplicate/neueswort",
"expected_result": "tests/api/expected-results/duplicate_neueswort.json",
},
]

#: The API endpoints
API_ENDPOINTS = (
DISCIPLINE_ENDPOINTS
Expand All @@ -396,6 +416,7 @@
+ GROUP_ENDPOINTS
+ FEEDBACK_ENDPOINTS
+ SPONSOR_ENDPOINTS
+ SEARCH_DUPLICATE_ENDPOINTS
)

#: Convert the dicts to tuples with a fixed length
Expand Down
6 changes: 6 additions & 0 deletions tests/api/expected-results/duplicate_Ei.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"message": "This word is already registered in the system.",
"word": "📷 (das) Ei (Nomen)",
"definition": "Definition: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua",
"training_sets": "Training sets: Zutaten"
}
6 changes: 6 additions & 0 deletions tests/api/expected-results/duplicate_Schere.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"message": "This word is already registered in the system.",
"word": "📷 (die) Schere (Nomen)",
"definition": "Definition: No definition is provided for this word.",
"training_sets": "Training sets: Grundlagen Werkzeuge, Grundlagen Rezeption"
}
6 changes: 6 additions & 0 deletions tests/api/expected-results/duplicate_implementieren.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"message": "This word is already registered in the system.",
"word": "⚠ (keiner) implementieren (Verb)",
"definition": "Definition: in ein bestehendes Computersystem einsetzen, einbauen und so ein funktionsfähiges Programm erstellen",
"training_sets": "Training sets: This word is assigned to no training set."
}
3 changes: 3 additions & 0 deletions tests/api/expected-results/duplicate_neueswort.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"message": "This word is not yet registered in the system"
}