From a1a3206f98eb488fe402a937505683d7deffe60f Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 27 Nov 2024 10:49:06 +0100 Subject: [PATCH 01/51] =?UTF-8?q?Abfrage=20hinzugef=C3=BCgt,=20um=20Text?= =?UTF-8?q?=20an=20Single=20oder=20multiplechoice=20Fragen=20anzupassen=20?= =?UTF-8?q?"Aktiviere=20die=20richtige=20Antwort"=20vs=20"Aktiviere=20alle?= =?UTF-8?q?=20richtigen=20Antworten"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/pages/QuestionEdit.tsx | 2 ++ 2 files changed, 6 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index c86aed5..633b83f 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -875,6 +875,10 @@ msgstr "Bearbeiten" msgid "activate-all-correct-answers" msgstr "Aktiviere alle richtigen Antworten" +#. js-lingui-explicit-id +msgid "activate-correct-answer" +msgstr "Aktiviere die richtige Antwort" + #. js-lingui-explicit-id #: src/pages/QuestionEdit.tsx:460 msgid "question-edit.button-tooltip.edit-answer" diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index 93013f2..f3cee5e 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -947,6 +947,8 @@ export const QuestionEdit: React.FC = () => {
+ {question.type === "SINGLE" && } + {question.type === "MULTIPLE" && }
{/* {isQuizTeacher && !shuffleAnswers ? ( */} {isActivateReorderAnswersVisible ? ( From d3e392154a3d368eb8f5b4cfd7bee41f4fc1a446 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 27 Nov 2024 11:36:35 +0100 Subject: [PATCH 02/51] quiz-student-participation angepasst --- packages/frontend/src/locales/de/messages.js | 2 +- packages/frontend/src/locales/de/messages.po | 2 +- packages/frontend/src/locales/en/messages.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.js b/packages/frontend/src/locales/de/messages.js index 92ba46a..edecbd4 100644 --- a/packages/frontend/src/locales/de/messages.js +++ b/packages/frontend/src/locales/de/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer existiert nicht\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer deaktivieren\",\"user-activate-user-button\":\"Benutzer aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten von Teilnehmenden\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator.\",\"error-message-user-deactivated-title\":\"Nutzer gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer existiert nicht\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer deaktivieren\",\"user-activate-user-button\":\"Benutzer aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator.\",\"error-message-user-deactivated-title\":\"Nutzer gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 633b83f..150e943 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -589,7 +589,7 @@ msgstr "Fragen durch Teilnehmende erstellen lassen" #: src/components/quiz-tabs/QuizDataTab.tsx:236 #: src/pages/CreateQuiz.tsx:98 msgid "quiz-student-participation" -msgstr "Teilnahmemöglichkeiten von Teilnehmenden" +msgstr "Teilnahmemöglichkeiten" #. js-lingui-explicit-id #: src/components/quiz-tabs/QuizDataTab.tsx:239 diff --git a/packages/frontend/src/locales/en/messages.js b/packages/frontend/src/locales/en/messages.js index 9bf5dc8..53d9968 100644 --- a/packages/frontend/src/locales/en/messages.js +++ b/packages/frontend/src/locales/en/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User doesn't exist\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participant participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User doesn't exist\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; From 0bf239cee9fcbef4ace8bd230777d561c91154b1 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 27 Nov 2024 15:56:03 +0100 Subject: [PATCH 03/51] Corrected the title length control to >0 instead of >3 --- packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx index 0352e6b..dc4c80a 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx @@ -179,7 +179,7 @@ export const QuizDataTab: React.FC = props => { setTitleAndDescription(prev => ({ ...prev, title: text })); - if (text.length > 3) { + if (text.length > 0) { updateDebounced({ title: text }); setTitleValidationError(""); } else { From 02e9788f659ab01c56aca1171227b235c29505a7 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 27 Nov 2024 16:55:36 +0100 Subject: [PATCH 04/51] Included TITLE_MIN_CHARACTER constant --- packages/frontend/src/actors/CreateQuizActor.ts | 4 +++- packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx | 4 ++-- packages/frontend/src/constants/constants.ts | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/actors/CreateQuizActor.ts b/packages/frontend/src/actors/CreateQuizActor.ts index 3466df9..bc21078 100644 --- a/packages/frontend/src/actors/CreateQuizActor.ts +++ b/packages/frontend/src/actors/CreateQuizActor.ts @@ -6,6 +6,8 @@ import { actorUris } from "../actorUris"; import unionize, { UnionOf, ofType } from "unionize"; import { clone, keys } from "rambda"; +import { TITLE_MIN_CHARACTERS } from "../constants/constants"; + export type NewQuiz = Omit; export const CreateQuizMessages = unionize( { @@ -70,7 +72,7 @@ export class CreateQuizActor extends StatefulActor => { const validation = { ...this.state.validation }; - validation.title = q.title.trim().length > 0; + validation.title = q.title.trim().length >= TITLE_MIN_CHARACTERS; // return validation; }; diff --git a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx index dc4c80a..cd2daa9 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx @@ -21,7 +21,7 @@ import { ButtonWithTooltip } from "../ButtonWithTooltip"; import { ShareQuizModal } from "../modals/ShareQuizModal"; import { checkIsCreatingQuestionDisabled, debounce } from "../../utils"; import { CharacterTracker } from "../CharacterTracker"; -import { DESCRIPTION_MAX_CHARACTERS, TITLE_MAX_CHARACTERS } from "../../constants/constants"; +import { DESCRIPTION_MAX_CHARACTERS, TITLE_MAX_CHARACTERS, TITLE_MIN_CHARACTERS } from "../../constants/constants"; import { useCurrentQuiz } from "../../hooks/state-actor/useCurrentQuiz"; // import { useCurrentQuiz } from "../../hooks/state-actor/useCurrentQuiz"; // import { keys } from "rambda"; @@ -179,7 +179,7 @@ export const QuizDataTab: React.FC = props => { setTitleAndDescription(prev => ({ ...prev, title: text })); - if (text.length > 0) { + if (text.length >= TITLE_MIN_CHARACTERS) { updateDebounced({ title: text }); setTitleValidationError(""); } else { diff --git a/packages/frontend/src/constants/constants.ts b/packages/frontend/src/constants/constants.ts index c7aee07..bba3ac3 100644 --- a/packages/frontend/src/constants/constants.ts +++ b/packages/frontend/src/constants/constants.ts @@ -1,2 +1,3 @@ export const TITLE_MAX_CHARACTERS = 150; export const DESCRIPTION_MAX_CHARACTERS = 1000; +export const TITLE_MIN_CHARACTERS = 1; From 291dd6974f04ab1b73931743a885ca4bf085b0cc Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Mon, 2 Dec 2024 11:46:08 +0100 Subject: [PATCH 05/51] =?UTF-8?q?Anpassung=20Quiz-Teilnahme,=20Texte=20und?= =?UTF-8?q?=20=C3=9Cbersetzungen,=20zus=C3=A4tzliche=20Properties=20f?= =?UTF-8?q?=C3=BCr=20Session=20und=20User.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/middlewares/authRoutes.ts | 1 + packages/frontend/src/Activate.tsx | 55 +++++++++++++++++-- packages/frontend/src/locales/de/messages.po | 23 ++++++++ packages/frontend/src/locales/en/messages.po | 25 +++++++++ packages/models/src/data/session.ts | 1 + packages/models/src/data/user.ts | 1 + 6 files changed, 101 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index 340ccbd..83a1217 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -105,6 +105,7 @@ export const authProviderCallback = async (ctx: koa.Context): Promise => { email: decoded.email ?? "", active: true, quizUsage: new Map(), + isTemporary: false, }) ); } else { diff --git a/packages/frontend/src/Activate.tsx b/packages/frontend/src/Activate.tsx index cb31e8b..c91843c 100644 --- a/packages/frontend/src/Activate.tsx +++ b/packages/frontend/src/Activate.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { Button, Modal } from "react-bootstrap"; import { Trans } from "@lingui/react"; import { useNavigate } from "react-router-dom"; @@ -8,6 +8,7 @@ export const Activate: React.FC = () => { const error = document.location.search.includes("error=userdeactivated"); const quiz = document.location.search.includes("quiz=") && document.location.search.split("=")[1]; const nav = useNavigate(); + const [showTempReminder, setShowTempReminder] = useState(false); useEffect(() => { if (cookie("bearer")) { @@ -19,23 +20,67 @@ export const Activate: React.FC = () => { return (
- Login-Fehler - Ihr Account wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator. + + + + + + + + + + + + + + + + + +

RECAPP

-
Melde dich an um am Quiz teilzunehmen.
+
+ +
+
oder
+ +
+ +
diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index c86aed5..47a9cc6 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1309,3 +1309,26 @@ msgstr "Vorschau beenden" msgid "quiz-button-label-start-preview" msgstr "Vorschau starten" +#. js-lingui-explicit-id +msgid "login-page.temporary-account-button" +msgstr "Ohne Anmeldung fortfahren" + +#. js-lingui-explicit-id +msgid "login-page.temp-login-header" +msgstr "Quizteilnahme ohne Anmeldung" + +#. js-lingui-explicit-id +msgid "login-page.temp-login-reminder" +msgstr "Du kannst ohne Anmeldung an dem Quiz teilnehmen. Um Missbrauch vorzubeugen, wird für deinen Browser und dein Gerät ein sogenannter Fingerprint erzeugt, mit dem wir dich während deiner Teilnahme identifzieren können. Dem stimmst du durch deine Teilnahme zu. Um dich später abzumelden, schließe einfach deinen Browser." + +#. js-lingui-explicit-id +msgid "login-page.info-text" +msgstr "Du kannst dich anmelden oder ohne Anmeldung am Quiz teilnehmen." + +#. js-lingui-explicit-id +msgid "login-page.account-deactivated-title" +msgstr "Login-Fehler. Account deaktiviert." + +#. js-lingui-explicit-id +msgid "login-page.account-deactivated-message" +msgstr "Ihr Account wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator." diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index eb3e37c..c1eaf26 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1312,3 +1312,28 @@ msgstr "End preview" #. js-lingui-explicit-id msgid "quiz-button-label-start-preview" msgstr "Start preview" + +#. js-lingui-explicit-id +msgid "login-page.temporary-account-button" +msgstr "Continue without login" + +#. js-lingui-explicit-id +msgid "login-page.temp-login-header" +msgstr "Participate without logging in" + +#. js-lingui-explicit-id +msgid "login-page.temp-login-reminder" +msgstr "You can participate in the quiz without logging in. To prevent abuse, a so-called fingerprint is created for your browser and device, which allows us to identify you during your participation. By participating, you agree to this. To log out later, simply close your browser." + +#. js-lingui-explicit-id +msgid "login-page.info-text" +msgstr "You can login with your account or participate without logging in." + +#. js-lingui-explicit-id +msgid "login-page.account-deactivated-title" +msgstr "Login error. Account deactivated." + +#. js-lingui-explicit-id +msgid "login-page.account-deactivated-message" +msgstr "Your account was deactivated. Please contact the administrator." + diff --git a/packages/models/src/data/session.ts b/packages/models/src/data/session.ts index 36ef95a..8e38c90 100644 --- a/packages/models/src/data/session.ts +++ b/packages/models/src/data/session.ts @@ -13,6 +13,7 @@ export const sessionSchema = zod.object({ role: userRoleSchema, created: timestampSchema, updated: timestampSchema, + fingerprint: zod.string().optional(), // Fingerprint, is set if this is a temporary account }); export type Session = zod.infer; diff --git a/packages/models/src/data/user.ts b/packages/models/src/data/user.ts index 5fb58e8..b749a23 100644 --- a/packages/models/src/data/user.ts +++ b/packages/models/src/data/user.ts @@ -23,6 +23,7 @@ export const userSchema = zod lastLogin: timestampSchema, // Date of last login active: zod.boolean(), // Whether the user can login quizUsage: zod.map(uidSchema, quizUsageType), // How the user decided to participate in each individual quiz + isTemporary: zod.boolean().optional().default(false), // Is this a temporary account }) .merge(idEntitySchema); From 225b013aa52ed565125ef848d3b6f4374d43317c Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Mon, 2 Dec 2024 17:12:09 +0100 Subject: [PATCH 06/51] JWT added to Template Temp account login routes User store adjustments Remove certain buttons for temp accounts --- .env.template | 2 + packages/backend/src/actors/UserStore.ts | 13 ++++ packages/backend/src/index.ts | 3 +- .../backend/src/middlewares/authRoutes.ts | 65 ++++++++++++++++- packages/backend/src/utils.ts | 67 +++++++++++++++++ .../src/components/quiz-tabs/QuizStatsTab.tsx | 72 ++++++++++--------- .../components/quizzes-panel/QuizzesPanel.tsx | 60 ++++++++-------- packages/models/src/messages/userStore.ts | 1 + 8 files changed, 219 insertions(+), 64 deletions(-) diff --git a/.env.template b/.env.template index 11b0b88..5fed5c7 100644 --- a/.env.template +++ b/.env.template @@ -14,3 +14,5 @@ API_KEYS=ADDUIDSYOUWANTTOUSEASAPIKEYS_AS_A_COMMA_SEPERATED_LIST MONGODB_PORT=26182 MONGODB_USER=recapp MONGODB_PW=YOURMONGOPW + +JWT_SECRET=YOURJWTSECRET diff --git a/packages/backend/src/actors/UserStore.ts b/packages/backend/src/actors/UserStore.ts index 749b752..058cede 100644 --- a/packages/backend/src/actors/UserStore.ts +++ b/packages/backend/src/actors/UserStore.ts @@ -134,6 +134,19 @@ export class UserStore extends SubscribableActor(identity, () => new Error(`User id ${userId} does not exist`)); }, + GetByFingerprint: async fp => { + if (!["ADMIN", "SYSTEM"].includes(clientUserRole)) { + return new Error(`Operation not allowed`); + } + const db = await this.connector.db(); + const maybeUser = maybe( + await db.collection(this.collectionName).findOne({ fingerprint: fp }) + ); + return maybeUser.match( + identity, + () => new Error(`User fingerprint ${fp} does not exist`) + ); + }, GetAll: async () => { if (!["ADMIN", "SYSTEM"].includes(clientUserRole)) { return new Error(`Operation not allowed`); diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 4d13cc0..a022429 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -16,7 +16,7 @@ import multer from "@koa/multer"; import type { File } from "@koa/multer"; import type { IncomingMessage } from "http"; import koaLogger from "koa-logger-winston"; -import { authLogin, authLogout, authProviderCallback, authRefresh } from "./middlewares/authRoutes"; +import { authLogin, authLogout, authProviderCallback, authRefresh, authTempAccount } from "./middlewares/authRoutes"; import { errorHandler } from "./middlewares/errorHandler"; import { logger } from "./logger"; import { authenticationMiddleware } from "./middlewares/authMiddleware"; @@ -56,6 +56,7 @@ router .get("/auth/callback", authProviderCallback) .get("/auth/logout", authLogout) .get("/auth/refresh", authRefresh) + .get("/auth/temp", authTempAccount) .get("/ping", ctx => { ctx.status = 200; ctx.body = "PONG"; diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index 83a1217..b6a8fb9 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -4,11 +4,12 @@ import { Issuer, Client, ClientMetadata } from "openid-client"; import Container from "typedi"; import koa from "koa"; import { ActorSystem } from "ts-actors"; -import { createActorUri } from "../utils"; +import { calculateFingerprint, createActorUri, createTempJwt } from "../utils"; import { Id, Session, SessionStoreMessages, User, UserRole, UserStoreMessages } from "@recapp/models"; import { toTimestamp } from "itu-utils"; import { DateTime } from "luxon"; import { maybe } from "tsmonads"; +import { v4 } from "uuid"; const { BACKEND_URI, OID_CLIENT_ID, OPENID_PROVIDER, ISSUER, OID_CLIENT_SECRET, REDIRECT_URI, REQUIRES_OFFLINE_SCOPE } = process.env; @@ -52,6 +53,62 @@ export const authLogin = async (ctx: koa.Context): Promise => { ctx.redirect(authUrl); }; +export const authTempAccount = async (ctx: koa.Context): Promise => { + // Fingerprint berechnen + const fingerprint = calculateFingerprint(ctx); + // Prüfen ob gesperrt + const system = Container.get("actor-system"); + const userStore = createActorUri("UserStore"); + try { + const existingUser: User | Error = await system.ask(userStore, UserStoreMessages.GetByFingerprint(fingerprint)); + if (existingUser instanceof Error) { + console.debug("A new fingerprint has been generated"); + } else if (!existingUser.active) { + ctx.redirect((process.env.FRONTEND_URI ?? "http://localhost:5173") + "?error=userdeactivated"); + return; + } + } catch (e) { + console.error(e); + } + // Wenn nicht, dann Token, temporären User und Session anlegen + const uid = v4() as Id; + const token = createTempJwt(uid, fingerprint); + const decoded = jwt.decode(token) as jwt.JwtPayload; + const sessionStore = createActorUri("SessionStore"); + const expires = DateTime.fromMillis((decoded.exp ?? -1) * 1000).toUTC(); + await system.send( + userStore, + UserStoreMessages.Create({ + uid, + role: "STUDENT", + lastLogin: toTimestamp(), + created: toTimestamp(), + updated: toTimestamp(), + username: "Temporary account", + email: "", + active: true, + quizUsage: new Map(), + isTemporary: true, + }) + ); + await system.send( + sessionStore, + SessionStoreMessages.StoreSession({ + idToken: token, + accessToken: token, + refreshToken: token, + uid, + idExpires: toTimestamp(expires), + refreshExpires: toTimestamp(expires), + role: "STUDENT", + fingerprint, + }) + ); + // Cookie setzen und zurückleiten + ctx.set("Set-Cookie", `bearer=${token}; path=/`); + ctx.redirect(process.env.FRONTEND_URI ?? "http://localhost:5173"); +}; + /** * Callback after login flow is finished * @@ -194,6 +251,12 @@ export const authRefresh = async (ctx: koa.Context): Promise => { ctx.set("Set-Cookie", `bearer=; path=/`); ctx.throw(401, "Session unknown"); } + // If this is a temporary account, just return + if (session.fingerprint) { + console.debug("Nothing to do for temporary account", session.fingerprint); + ctx.body = "O.K."; + return; + } try { const newTokenSet = await client.refresh(session.refreshToken); const decoded = jwt.decode(newTokenSet.id_token ?? "") as jwt.JwtPayload; diff --git a/packages/backend/src/utils.ts b/packages/backend/src/utils.ts index 263fb4e..64f5fcc 100644 --- a/packages/backend/src/utils.ts +++ b/packages/backend/src/utils.ts @@ -6,6 +6,8 @@ import { ActorRef, ActorSystem } from "ts-actors"; import { maybe } from "tsmonads"; import Container from "typedi"; import jwt from "jsonwebtoken"; +import koa from "koa"; +import crypto from "crypto"; export const systemName = "recapp-backend"; @@ -37,3 +39,68 @@ export const bearerValid = async (idTokenString: string): Promise => { return Promise.reject(new Error("Unknown user")); } }; + +export const calculateFingerprint = (ctx: koa.Context): string => { + const components = { + userAgent: ctx.get("user-agent") || "", + acceptLanguage: ctx.get("accept-language") || "", + accept: ctx.get("accept") || "", + acceptEncoding: ctx.get("accept-encoding") || "", + + ip: ctx.ip || "", + + secChUa: ctx.get("sec-ch-ua") || "", + secChUaPlatform: ctx.get("sec-ch-ua-platform") || "", + secChUaMobile: ctx.get("sec-ch-ua-mobile") || "", + + doNotTrack: ctx.get("dnt") || "", + + protocol: ctx.protocol || "", + host: ctx.host || "", + origin: ctx.origin || "", + + deviceMemory: ctx.get("device-memory") || "", + hardwareConcurrency: ctx.get("hardware-concurrency") || "", + }; + + const fingerprintString = Object.entries(components) + .sort(([keyA], [keyB]) => keyA.localeCompare(keyB)) + .map(([key, value]) => `${key}:${value}`) + .join("|"); + + const hash = crypto.createHash("sha256").update(fingerprintString).digest("hex"); + + return hash; +}; + +const JWT_SECRET = process.env.JWT_SECRET; + +export const createTempJwt = (userId: Id, fingerprint: string): any => { + if (!JWT_SECRET) { + throw new Error("New secret for JWT generation set in server env"); + } + + const payload: jwt.JwtPayload = { + userId: fingerprint, + sub: userId, + role: "TEMP", + }; + + const options: jwt.SignOptions = { + expiresIn: "30d", + algorithm: "HS256", + audience: "users", + issuer: "recapp", + }; + + // Optionen zusammenführen, übergebene überschreiben defaults + + try { + // Token erstellen + const token = jwt.sign(payload, JWT_SECRET as jwt.Secret, options); + return token; + } catch (error) { + console.error("Error on creating token:", error); + throw error; + } +}; diff --git a/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx index bfdc3b7..b4e70e2 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx @@ -27,6 +27,8 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat const run = mbQuiz.flatMap(q => (q?.result && Object.keys(q.result).length > 0 ? maybe(q?.result) : nothing())); const counter = run.map(r => r.counter).orElse(0); + const isTemporaryAccount = mbUser.map(u => u.user.isTemporary).orElse(false); + // TODO Eigene Ergebnisse für das Quiz holen useEffect(() => { if (tryActor.succeeded) { @@ -34,12 +36,12 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat .map(u => u.user.uid) .forEach(userId => { // const isStudent = mbQuiz.map(q => q.quiz.students.includes(uid)).orElse(false); - const quizData = mbQuiz - .flatMap(q => (keys(q.quiz).length > 0 ? maybe(q) : nothing())) - .match( - quizData => quizData, - () => null - ); + const quizData = mbQuiz + .flatMap(q => (keys(q.quiz).length > 0 ? maybe(q) : nothing())) + .match( + quizData => quizData, + () => null + ); const isUserInStudentsList = quizData ? isInStudentList(quizData.quiz, userId) : true; console.log("STUD", isUserInStudentsList, run); if (isUserInStudentsList && run.hasValue) { @@ -135,7 +137,7 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat
- {i == 0 && !isPresentationModeActive && ( + {i == 0 && !isPresentationModeActive && !isTemporaryAccount && ( <> = ({ quizDat )}
- {group.questions.map((qId, index, arr)=> { + {group.questions.map((qId, index, arr) => { const isLast = arr.length - 1 === index; // This is the overview of all questions const statIndex = quizStats.questionIds.findIndex(f => f === qId)!; @@ -174,7 +176,7 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat key={questionId + index + qId} className="m-1xx p-2 pt-3 pb-3" // style={{ backgroundColor: "lightgrey" }} - style={{ borderBottom: !isLast ? "2px solid lightgray" : undefined }} + style={{ borderBottom: !isLast ? "2px solid lightgray" : undefined }} >
@@ -190,9 +192,9 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat tryActor.forEach(actor => actor.send( actor, - CurrentQuizMessages.ActivateQuestionStats( - questionId - ) + CurrentQuizMessages.ActivateQuestionStats( + questionId + ) ) ) } @@ -223,28 +225,30 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat
- {!isNil(ownCorrectAnswers[qId]) && ( - <> - {/* (:{" "} */} - {/* {ownCorrect ? CHECK_SYMBOL : X_SYMBOL}) */} - - ({ownCorrect ? ( - - ) : ( - - )}) - - {/* ) */} - - )} + {!isNil(ownCorrectAnswers[qId]) && ( + <> + {/* (:{" "} */} + {/* {ownCorrect ? CHECK_SYMBOL : X_SYMBOL}) */} + + ( + {ownCorrect ? ( + + ) : ( + + )} + ) + + {/* ) */} + + )}
{noDetails ? ( diff --git a/packages/frontend/src/components/quizzes-panel/QuizzesPanel.tsx b/packages/frontend/src/components/quizzes-panel/QuizzesPanel.tsx index 0b96c83..e679050 100644 --- a/packages/frontend/src/components/quizzes-panel/QuizzesPanel.tsx +++ b/packages/frontend/src/components/quizzes-panel/QuizzesPanel.tsx @@ -18,7 +18,7 @@ import { TooltipWrapper } from "../TooltipWrapper"; export const QuizzesPanel: React.FC = () => { const nav = useNavigate(); - const [filter, setFilter] = useState(""); + const [filter, setFilter] = useState(""); const [shareModal, setShareModal] = useState(""); const [deleteModal, setDeleteModal] = useState(toId("")); const [showDelete, setShowDelete] = useState(false); @@ -56,6 +56,8 @@ export const QuizzesPanel: React.FC = () => { ); }, [state]); + const isNotTemporaryAccount = state.map(s => !s.user?.isTemporary).orElse(true); + const archiveAllowed = (quiz: Partial): true | undefined => { const isAdmin = state .map(s => s.user) @@ -90,7 +92,7 @@ export const QuizzesPanel: React.FC = () => { setDeleteModal(toId("")); }; - const filteredQuizzes = (quizzes ?? []).filter(u => u.title?.toLocaleLowerCase().includes(filter)); + const filteredQuizzes = (quizzes ?? []).filter(u => u.title?.toLocaleLowerCase().includes(filter)); return ( <> @@ -107,22 +109,24 @@ export const QuizzesPanel: React.FC = () => { setShareModal("")} />
-
- - -
+ {isNotTemporaryAccount && ( +
+ + +
+ )} @@ -139,16 +143,16 @@ export const QuizzesPanel: React.FC = () => {
-
- s.showArchived).orElse(false)} - onChange={event => - tryLocalUserActor.forEach(q => q.send(q, new ToggleShowArchived(event.target.checked))) - } - /> -
+
+ s.showArchived).orElse(false)} + onChange={event => + tryLocalUserActor.forEach(q => q.send(q, new ToggleShowArchived(event.target.checked))) + } + /> +
{filteredQuizzes.map(q => { return ( (), // Get user, answers with User GetOwn: {}, // Return the info of the requesting user, answers with User GetRole: ofType(), // Return the role of the given user, answers with UserRole + GetByFingerprint: ofType(), // Return a user for the given fingerprint GetNames: ofType>(), // Return the names for the given User Ids SubscribeTo: ofType(), // Subscribe to all changes of the specific user, sends back all updates to requester SubscribeToCollection: ofType(), // Subscribe to all changes of the specific user, sends back all updates to requester. Returns only the requested properties. From 41b4f2cbc76d93368a307558101301c2beb5d3ed Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 4 Dec 2024 11:32:55 +0100 Subject: [PATCH 07/51] Bug fix --- packages/frontend/src/pages/QuestionEdit.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index f3cee5e..3690fa2 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -946,7 +946,6 @@ export const QuestionEdit: React.FC = () => {
- {question.type === "SINGLE" && } {question.type === "MULTIPLE" && }
From 804ccd062d43a301338fc47b51d895d6ca12fb24 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 4 Dec 2024 11:42:52 +0100 Subject: [PATCH 08/51] Bug fix 2: change multiple and single to match the correct question type (activate correct answers message --- packages/frontend/src/pages/QuestionEdit.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index 3690fa2..3b381c9 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -946,8 +946,8 @@ export const QuestionEdit: React.FC = () => {
- {question.type === "SINGLE" && } - {question.type === "MULTIPLE" && } + {question.type === "MULTIPLE" && } + {question.type === "SINGLE" && }
{/* {isQuizTeacher && !shuffleAnswers ? ( */} {isActivateReorderAnswersVisible ? ( From 212b1225e35268bcc8c3fb4bf463ed5a2805a109 Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Thu, 5 Dec 2024 16:11:03 +0100 Subject: [PATCH 09/51] =?UTF-8?q?EIntrittsquiz=20an=20temp=20accounts=20sp?= =?UTF-8?q?eichern.=20Beim=20Logout=20Sessions=20verwerfen=20Beim=20Logout?= =?UTF-8?q?=20Temp=20User=20l=C3=B6schen=20Operationen=20f=C3=BCr=20Temp?= =?UTF-8?q?=20User=20unterbinden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/actors/QuizActor.ts | 14 +++++- packages/backend/src/actors/StoringActor.ts | 10 ++--- packages/backend/src/actors/UserStore.ts | 45 ++++++++++++++++++- .../backend/src/middlewares/authRoutes.ts | 37 +++++++++++++++ packages/frontend/src/Activate.tsx | 2 +- .../src/components/quiz-tabs/QuizStatsTab.tsx | 7 +-- packages/models/src/data/user.ts | 1 + packages/models/src/messages/userStore.ts | 1 + 8 files changed, 104 insertions(+), 13 deletions(-) diff --git a/packages/backend/src/actors/QuizActor.ts b/packages/backend/src/actors/QuizActor.ts index e2610f1..861a232 100644 --- a/packages/backend/src/actors/QuizActor.ts +++ b/packages/backend/src/actors/QuizActor.ts @@ -200,9 +200,12 @@ export class QuizActor extends SubscribableActor { console.log("QUIZACTOR", from.name, message); try { - const [clientUserRole, clientUserId] = await this.determineRole(from); + const [clientUserRole, clientUserId, clientIsTemporary] = await this.determineRole(from); return await QuizActorMessages.match>(message, { Create: async quiz => { + if (clientIsTemporary){ + return serializeError(new Error("Cannot export as a temporary user")); + } return this.create(quiz, clientUserRole, clientUserId); }, GetUserRun: async ({ studentId, quizId }) => { @@ -385,6 +388,9 @@ export class QuizActor extends SubscribableActor { + if (clientIsTemporary){ + return serializeError(new Error("Cannot export as a temporary user")); + } console.log(filename); const jsonBuffer = await readFile(path.join("./downloads", filename)); const importedObject = JSON.parse(jsonBuffer.toString()); @@ -469,6 +475,9 @@ export class QuizActor extends SubscribableActor { + if (clientIsTemporary){ + return serializeError(new Error("Cannot export as a temporary user")); + } const db = await this.connector.db(); const mbQuiz = maybe(await db.collection(this.collectionName).findOne({ uid })); return mbQuiz.match>( @@ -516,6 +525,9 @@ export class QuizActor extends SubscribableActor { + if (clientIsTemporary){ + return serializeError(new Error("Cannot export as a temporary user")); + } try { const filename = (await this.ask(this.ref, QuizActorMessages.Export(uid))) as string | Error; if (typeof filename === "string") { diff --git a/packages/backend/src/actors/StoringActor.ts b/packages/backend/src/actors/StoringActor.ts index 3280da6..296508a 100644 --- a/packages/backend/src/actors/StoringActor.ts +++ b/packages/backend/src/actors/StoringActor.ts @@ -39,13 +39,13 @@ export abstract class StoringActor => { + protected determineRole = async (from: ActorRef): Promise<[UserRole: AccessRole, UserID: Id, IsTemporaryAccount: boolean]> => { if (systemEquals(this.actorRef!, from)) { - return ["SYSTEM", "SYSTEM" as Id]; + return ["SYSTEM", "SYSTEM" as Id, false]; } if (extractSystemName(this.actorRef!.name) === from.name.replace("actors://", "")) { // It's our actor system that's asking directly - return ["SYSTEM", "SYSTEM" as Id]; + return ["SYSTEM", "SYSTEM" as Id, false]; } const session: Session = await this.ask( @@ -55,9 +55,9 @@ export abstract class StoringActor s as Session) .catch((e: Error): Session => { console.error(e); - return { role: "STUDENT", uid: "" } as Session; + return { role: "STUDENT", uid: "", fingerprint: "-"} as Session; }); - return [session.role, session.uid]; + return [session.role, session.uid, !!session.fingerprint]; }; protected async afterEntityRemovedFromCache(_uid: Id) { diff --git a/packages/backend/src/actors/UserStore.ts b/packages/backend/src/actors/UserStore.ts index 058cede..ea9e16f 100644 --- a/packages/backend/src/actors/UserStore.ts +++ b/packages/backend/src/actors/UserStore.ts @@ -19,6 +19,9 @@ import { CollecionSubscription, SubscribableActor } from "./SubscribableActor"; import { AccessRole } from "./StoringActor"; import { maybe } from "tsmonads"; import { createActorUri } from "../utils"; +import { DateTime } from "luxon"; + +const REMOVE_TEMPS_INTERVAL = 1; // 30; // 30 days type ListedUser = Omit; @@ -66,6 +69,25 @@ export class UserStore extends SubscribableActor { + const cleanupTimestamp = toTimestamp(DateTime.utc().minus({ days: REMOVE_TEMPS_INTERVAL })); + const db = await this.connector.db() + const temporaryUsers = await db.collection(this.collectionName).find({ isTemporary: true }).toArray(); + temporaryUsers.forEach(user => { + if (user.lastLogin < cleanupTimestamp) { + this.logger.debug(`Deleting old temporary user ${user.uid} ${user.username}`); + db.collection(this.collectionName).deleteOne({ uid: user.uid }); + this.state.lastTouched.delete(user.uid); + this.state.cache.delete(user.uid); + this.afterEntityRemovedFromCache(user.uid); + } + }) + } + cleanupTemps(); + } + public async receive(from: ActorRef, message: UserStoreMessage): Promise { console.log("USERSTORE", from.name, message); try { @@ -155,7 +177,9 @@ export class UserStore extends SubscribableActor(this.collectionName).find({}).toArray(); users.forEach(user => { const { _id, quizUsage, ...rest } = user; - this.send(from, new UserUpdateMessage(rest)); + if (clientUserRole === "SYSTEM" || !rest.isTemporary) { + this.send(from, new UserUpdateMessage(rest)); + } }); return unit(); }, @@ -245,6 +269,25 @@ export class UserStore extends SubscribableActor { + const db = await this.connector.db(); + const mbUser = maybe(await db.collection(this.collectionName).findOne({uid})); + return mbUser.match( + user => { + if (user.isTemporary) { + this.deleteEntity(user.uid); + this.state.lastTouched.delete(uid); + this.state.cache.delete(uid); + } else { + this.logger.warn(`Trying to remove non-temporary user ${uid}. Operation not allowed and therefore skipped.`); + } + return unit(); + }, + () => { + return new Error(`User not found with id <${uid}>`); + } + ) + }, default: async () => { return new Error(`Unknown message ${JSON.stringify(message)} from ${from.name}`); }, diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index b6a8fb9..841406c 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -56,6 +56,7 @@ export const authLogin = async (ctx: koa.Context): Promise => { export const authTempAccount = async (ctx: koa.Context): Promise => { // Fingerprint berechnen const fingerprint = calculateFingerprint(ctx); + const quiz = ctx.query.quiz?.toString(); // Prüfen ob gesperrt const system = Container.get("actor-system"); const userStore = createActorUri("UserStore"); @@ -89,6 +90,7 @@ export const authTempAccount = async (ctx: koa.Context): Promise => { active: true, quizUsage: new Map(), isTemporary: true, + initialQuiz: quiz && quiz !== "false" ? quiz : undefined, }) ); await system.send( @@ -216,6 +218,41 @@ export const authProviderCallback = async (ctx: koa.Context): Promise => { * Also performs a local session logout. */ export const authLogout = async (ctx: koa.Context): Promise => { + const maybeIdToken = maybe(ctx.request.headers.cookie) + .flatMap(cookie => maybe(/bearer=([^;]+)/.exec(cookie))) + .flatMap(match => maybe(match[1])); + + await maybeIdToken.match( + async idToken => { + try { + const { sub } = jwt.decode(idToken) as jwt.JwtPayload; + const system = Container.get("actor-system"); + const sessionStore = createActorUri("SessionStore"); + const session: Session = await system + .ask(sessionStore, SessionStoreMessages.GetSessionForUserId(sub as Id)) + .then(s => s as Session) + .catch((e: Error) => { + return e; + }); + await system.send(sessionStore, SessionStoreMessages.RemoveSession(session.uid)); + if (session.fingerprint) { + const userStore = createActorUri("UserStore"); + await system.send( + userStore, + UserStoreMessages.Remove(session.uid) + ); + } + } catch (e) { + console.error("authLogout", e); + throw e; + } + }, + () => ctx.throw(401, "Unable to sign out.") + ); + + // TODO - Remove the session from the session store + + // TODO - Remove the user if it is a temporary user ctx.set("Set-Cookie", `bearer=; path=/; max-age=0`); ctx.redirect(process.env.FRONTEND_URI ?? "http://localhost:5173"); }; diff --git a/packages/frontend/src/Activate.tsx b/packages/frontend/src/Activate.tsx index c91843c..d30f7e3 100644 --- a/packages/frontend/src/Activate.tsx +++ b/packages/frontend/src/Activate.tsx @@ -39,7 +39,7 @@ export const Activate: React.FC = () => { variant="primary" className="m-4" style={{ maxWidth: 150 }} - href={`${import.meta.env.VITE_BACKEND_URI}/auth/temp`} + href={`${import.meta.env.VITE_BACKEND_URI}/auth/temp?quiz=${quiz}`} > diff --git a/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx index b4e70e2..dceba79 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizStatsTab.tsx @@ -27,13 +27,12 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat const run = mbQuiz.flatMap(q => (q?.result && Object.keys(q.result).length > 0 ? maybe(q?.result) : nothing())); const counter = run.map(r => r.counter).orElse(0); - const isTemporaryAccount = mbUser.map(u => u.user.isTemporary).orElse(false); + const isTemporaryAccount = mbUser.flatMap(u => maybe(u.user.isTemporary)).orElse(false); - // TODO Eigene Ergebnisse für das Quiz holen useEffect(() => { if (tryActor.succeeded) { mbUser - .map(u => u.user.uid) + .flatMap(u => maybe(u.user.uid)) .forEach(userId => { // const isStudent = mbQuiz.map(q => q.quiz.students.includes(uid)).orElse(false); const quizData = mbQuiz @@ -60,13 +59,11 @@ export const QuizStatsTab: React.FC<{ quizData: CurrentQuizState }> = ({ quizDat }, [tryActor.succeeded, counter]); const exportQuiz = () => { - // TODO: Fragen ob csv oder pdf setShowExportModal(true); tryActor.forEach(actor => actor.send(actor, CurrentQuizMessages.ExportQuizStats())); }; const exportQuestions = () => { - // TODO: Fragen ob csv oder pdf setShowExportModal(true); tryActor.forEach(actor => actor.send(actor, CurrentQuizMessages.ExportQuestionStats())); }; diff --git a/packages/models/src/data/user.ts b/packages/models/src/data/user.ts index b749a23..5266fad 100644 --- a/packages/models/src/data/user.ts +++ b/packages/models/src/data/user.ts @@ -24,6 +24,7 @@ export const userSchema = zod active: zod.boolean(), // Whether the user can login quizUsage: zod.map(uidSchema, quizUsageType), // How the user decided to participate in each individual quiz isTemporary: zod.boolean().optional().default(false), // Is this a temporary account + initialQuiz: zod.string().optional(), // Initial quiz, if any (will be set if the user logged in or was created with a link) }) .merge(idEntitySchema); diff --git a/packages/models/src/messages/userStore.ts b/packages/models/src/messages/userStore.ts index ed3a022..6e75944 100644 --- a/packages/models/src/messages/userStore.ts +++ b/packages/models/src/messages/userStore.ts @@ -20,6 +20,7 @@ export const UserStoreMessages = unionize( UnsubscribeFromCollection: {}, // Unsubscribe from collection changes GetTeachers: {}, // Returns a list of minimal information on all teachers (uid, name, pseudonym) IsNicknameUnique: ofType(), // Returns a boolean to signal whether the given pseudonym is unique. Note that you should not test for the user's own nickname since this will always be false + Remove: ofType(), // Removes a temporary user from the user store and db }, { tag: "UserStoreMessage", value: "value" } ); From dddacb9afcfa053e7c0e5870f9cfc50137492611 Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Thu, 5 Dec 2024 17:02:28 +0100 Subject: [PATCH 10/51] Type corrections --- packages/backend/src/middlewares/authRoutes.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index 841406c..f14c97b 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -228,12 +228,15 @@ export const authLogout = async (ctx: koa.Context): Promise => { const { sub } = jwt.decode(idToken) as jwt.JwtPayload; const system = Container.get("actor-system"); const sessionStore = createActorUri("SessionStore"); - const session: Session = await system + const session: Session | Error = await system .ask(sessionStore, SessionStoreMessages.GetSessionForUserId(sub as Id)) .then(s => s as Session) .catch((e: Error) => { return e; }); + if (session instanceof Error) { + throw session; + } await system.send(sessionStore, SessionStoreMessages.RemoveSession(session.uid)); if (session.fingerprint) { const userStore = createActorUri("UserStore"); From 3129a6080a4bf623e82ec7cdc9148ce75805a89b Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Sat, 7 Dec 2024 13:14:51 +0100 Subject: [PATCH 11/51] Added activate-correct-answer msgid to the js files --- packages/frontend/src/locales/de/messages.js | 2 +- packages/frontend/src/locales/en/messages.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.js b/packages/frontend/src/locales/de/messages.js index edecbd4..4244bc7 100644 --- a/packages/frontend/src/locales/de/messages.js +++ b/packages/frontend/src/locales/de/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer existiert nicht\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer deaktivieren\",\"user-activate-user-button\":\"Benutzer aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator.\",\"error-message-user-deactivated-title\":\"Nutzer gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer existiert nicht\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer deaktivieren\",\"user-activate-user-button\":\"Benutzer aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"activate-correct-answer\":\"Aktiviere die richtige Antwort\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator.\",\"error-message-user-deactivated-title\":\"Nutzer gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; diff --git a/packages/frontend/src/locales/en/messages.js b/packages/frontend/src/locales/en/messages.js index 53d9968..ec76555 100644 --- a/packages/frontend/src/locales/en/messages.js +++ b/packages/frontend/src/locales/en/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User doesn't exist\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User doesn't exist\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"activate-correct-answer\":\"Activate the correct answer\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; From 92287d768f21159fe397f8e0308f04782829c04b Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Sat, 7 Dec 2024 13:20:36 +0100 Subject: [PATCH 12/51] activate-correct-answer somehow must have gotten lost in the first commit? This should have been in the po file already? Anyways, now it's getting pushed :) --- packages/frontend/src/locales/en/messages.po | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index eb3e37c..e35c962 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -592,7 +592,7 @@ msgstr "Allow participants to set questions" #: src/components/quiz-tabs/QuizDataTab.tsx:236 #: src/pages/CreateQuiz.tsx:98 msgid "quiz-student-participation" -msgstr "Participant participation options" +msgstr "Participation options" #. js-lingui-explicit-id #: src/components/quiz-tabs/QuizDataTab.tsx:239 @@ -874,6 +874,10 @@ msgstr "Edit title" msgid "activate-all-correct-answers" msgstr "Activate all correct answers" +#. js-lingui-explicit-id +msgid "activate-correct-answer" +msgstr "Activate the correct answer" + #. js-lingui-explicit-id #: src/pages/QuestionEdit.tsx:460 msgid "question-edit.button-tooltip.edit-answer" From 4a14d2d5aa8e1136917c5bb9d95b4c92f3da5562 Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Mon, 9 Dec 2024 14:17:41 +0100 Subject: [PATCH 13/51] Bugfxies temp accounts, Fingerprint storage. --- .../backend/src/actors/FingerprintStore.ts | 113 ++++++++++++++++++ packages/backend/src/index.ts | 2 + .../backend/src/middlewares/authRoutes.ts | 23 ++-- packages/frontend/src/Activate.tsx | 16 ++- packages/frontend/src/locales/de/messages.po | 6 +- packages/frontend/src/locales/en/messages.po | 6 +- packages/frontend/src/pages/QuestionEdit.tsx | 3 +- packages/frontend/src/pages/QuizPage.tsx | 18 ++- packages/models/src/data/session.ts | 12 ++ packages/models/src/index.ts | 1 + .../models/src/messages/fingerprintStore.ts | 21 ++++ 11 files changed, 200 insertions(+), 21 deletions(-) create mode 100644 packages/backend/src/actors/FingerprintStore.ts create mode 100644 packages/models/src/messages/fingerprintStore.ts diff --git a/packages/backend/src/actors/FingerprintStore.ts b/packages/backend/src/actors/FingerprintStore.ts new file mode 100644 index 0000000..92847a2 --- /dev/null +++ b/packages/backend/src/actors/FingerprintStore.ts @@ -0,0 +1,113 @@ +import { Timestamp, Unit, toTimestamp, unit } from "itu-utils"; +import { ActorRef, ActorSystem } from "ts-actors"; +import { create } from "mutative"; +import { ActorUri, Fingerprint, FingerprintStoreMessage, FingerprintStoreMessages, FingerprintUpdateMessage, Id } from "@recapp/models"; +import { pick } from "rambda"; +import { CollecionSubscription, SubscribableActor } from "./SubscribableActor"; + +type FingerprintStoreResult = Unit | Error | Fingerprint | boolean; + +type FingerprintStoreState = { + cache: Map; + lastTouched: Map; + subscribers: Map>; + collectionSubscribers: Map; + lastSeen: Map; +}; + +export class FingerprintStore extends SubscribableActor { + protected override state: FingerprintStoreState = { cache: new Map(), lastTouched: new Map(), subscribers: new Map(), collectionSubscribers: new Map(), lastSeen: new Map() }; + + public constructor(name: string, system: ActorSystem) { + super(name, system, "fingerprints"); + } + + protected override updateIndices(_draft: FingerprintStoreState, _entity: Fingerprint): void { + // No index needed for fingerprints + } + + private updateSubscribers(fingerprint: Partial & { uid : Id }) { + for (const [subscriber, subscription] of this.state.collectionSubscribers) { + this.send( + subscriber, + new FingerprintUpdateMessage( + subscription.properties.length > 0 + ? pick(subscription.properties, fingerprint) + : fingerprint + ) + ); + } + for (const subscriber of this.state.subscribers.get(fingerprint.uid) ?? new Set()) { + this.send(subscriber, new FingerprintUpdateMessage(fingerprint)); + } + } + + public async receive(from: ActorRef, message: FingerprintStoreMessage): Promise { + const [clientUserRole] = await this.determineRole(from); + if (!["ADMIN", "SYSTEM"].includes(clientUserRole)) { + return new Error(`Operation not allowed`); + } + const result = await FingerprintStoreMessages.match>(message, { + StoreFingerprint: async session => { + this.state = await create(this.state, async draft => { + const currentSession = (await this.getEntity(session.uid)).orElse({} as Fingerprint); + session.updated = toTimestamp(); + const newSession = { ...currentSession, ...session }; + draft.cache.set(session.uid, newSession); + this.storeEntity(newSession); + }); + return unit(); + }, + Block: async id => { + const mbFingerprint = await this.getEntity(id) + return mbFingerprint.match( + fp => { + this.storeEntity({...fp, blocked: true}); + this.updateSubscribers({...fp, blocked: true}) + return unit(); + }, + () => { + return new Error(`Unknown fingerprint id ${id}`); + } + ) + }, + Unblock: async id => { + const mbFingerprint = await this.getEntity(id) + return mbFingerprint.match( + fp => { + this.storeEntity({...fp, blocked: false}); + this.updateSubscribers({...fp, blocked: true}) + return unit(); + }, + () => { + return new Error(`Unknown fingerprint id ${id}`); + } + ) + }, + IncreaseCount: async id => { + const mbFingerprint = await this.getEntity(id) + return mbFingerprint.match( + fp => { + this.storeEntity({...fp, usageCount: fp.usageCount + 1}); + this.updateSubscribers({...fp, blocked: true}) + return unit(); + }, + () => { + return new Error(`Unknown fingerprint id ${id}`); + } + ) + }, + GetMostRecent: async () => { + const db = await this.connector.db(); + const fps = await db.collection(this.collectionName).find({}).sort({lastSeen: 1}).limit(100).toArray(); + fps.forEach(fp => { + const { _id, ...rest } = fp; + this.send(from, new FingerprintUpdateMessage(rest)); + }); + return unit(); + }, + default: async () => new Error(`Unknown message from ${from.name}`), + }); + return result; + } +} diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index a022429..e3c7d7a 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -24,6 +24,7 @@ import { QuizActor } from "./actors/QuizActor"; import { ErrorActor } from "./actors/ErrorActor"; import { createReadStream, existsSync } from "fs"; import * as path from "path"; +import { FingerprintStore } from "./actors/FingerprintStore"; const config = { port: parseInt(process.env.SERVER_PORT ?? "3123"), @@ -106,6 +107,7 @@ const start = async () => { const system = await DistributedActorSystem.create({ distributor, systemName, logger }); Container.set("actor-system", system); await system.createActor(SessionStore, { name: "SessionStore", strategy: "Restart" }); + await system.createActor(FingerprintStore, { name: "FingerprintStore", strategy: "Restart" }); await system.createActor(UserStore, { name: "UserStore", strategy: "Restart" }); await system.createActor(QuizActor, { name: "QuizActor", strategy: "Restart" }); await system.createActor(ErrorActor, { name: "ErrorActor", strategy: "Restart", errorReceiver: true }); diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index f14c97b..5a3db9d 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -57,6 +57,7 @@ export const authTempAccount = async (ctx: koa.Context): Promise => { // Fingerprint berechnen const fingerprint = calculateFingerprint(ctx); const quiz = ctx.query.quiz?.toString(); + const persistentCookie = !!ctx.query.persistent; // Prüfen ob gesperrt const system = Container.get("actor-system"); const userStore = createActorUri("UserStore"); @@ -103,11 +104,14 @@ export const authTempAccount = async (ctx: koa.Context): Promise => { idExpires: toTimestamp(expires), refreshExpires: toTimestamp(expires), role: "STUDENT", + persistentCookie, fingerprint, }) ); // Cookie setzen und zurückleiten - ctx.set("Set-Cookie", `bearer=${token}; path=/`); + const thirtyDaysFromNow = new Date(); + thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30); + ctx.set("Set-Cookie", `bearer=${token}; path=/; Expires=${thirtyDaysFromNow.toUTCString()}`); ctx.redirect(process.env.FRONTEND_URI ?? "http://localhost:5173"); }; @@ -253,9 +257,6 @@ export const authLogout = async (ctx: koa.Context): Promise => { () => ctx.throw(401, "Unable to sign out.") ); - // TODO - Remove the session from the session store - - // TODO - Remove the user if it is a temporary user ctx.set("Set-Cookie", `bearer=; path=/; max-age=0`); ctx.redirect(process.env.FRONTEND_URI ?? "http://localhost:5173"); }; @@ -269,14 +270,7 @@ export const authRefresh = async (ctx: koa.Context): Promise => { async idToken => { try { const { sub } = jwt.decode(idToken) as jwt.JwtPayload; - /* if (fromTimestamp(exp! * 1000) < DateTime.local().minus(minutes(45))) { - console.log("Refresh not needed yet"); - console.log( - `Session ${fromTimestamp(exp! * 1000).toISO()} < ${DateTime.local().minus(minutes(45))}` - ); - ctx.body = "O.K."; - return; // We do not need to refresh the token yet - } */ + // Refresh the token const client = await getOidc(); const system = Container.get("actor-system"); @@ -293,7 +287,10 @@ export const authRefresh = async (ctx: koa.Context): Promise => { } // If this is a temporary account, just return if (session.fingerprint) { - console.debug("Nothing to do for temporary account", session.fingerprint); + const token = createTempJwt(session.uid, session.fingerprint); + const thirtyDaysFromNow = new Date(); + thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30); + ctx.set("Set-Cookie", `bearer=${token}; path=/; expires=${thirtyDaysFromNow.toUTCString()}`); ctx.body = "O.K."; return; } diff --git a/packages/frontend/src/Activate.tsx b/packages/frontend/src/Activate.tsx index d30f7e3..05fe42b 100644 --- a/packages/frontend/src/Activate.tsx +++ b/packages/frontend/src/Activate.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { Button, Modal } from "react-bootstrap"; +import { Button, Modal, Form } from "react-bootstrap"; import { Trans } from "@lingui/react"; import { useNavigate } from "react-router-dom"; import { cookie } from "./utils"; @@ -9,6 +9,7 @@ export const Activate: React.FC = () => { const quiz = document.location.search.includes("quiz=") && document.location.search.split("=")[1]; const nav = useNavigate(); const [showTempReminder, setShowTempReminder] = useState(false); + const [persistentCookie, setPersistentCookie] = useState(true); useEffect(() => { if (cookie("bearer")) { @@ -33,13 +34,24 @@ export const Activate: React.FC = () => { + + + + + setPersistentCookie(event.target.checked)} + /> + diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 47a9cc6..8982904 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1319,7 +1319,11 @@ msgstr "Quizteilnahme ohne Anmeldung" #. js-lingui-explicit-id msgid "login-page.temp-login-reminder" -msgstr "Du kannst ohne Anmeldung an dem Quiz teilnehmen. Um Missbrauch vorzubeugen, wird für deinen Browser und dein Gerät ein sogenannter Fingerprint erzeugt, mit dem wir dich während deiner Teilnahme identifzieren können. Dem stimmst du durch deine Teilnahme zu. Um dich später abzumelden, schließe einfach deinen Browser." +msgstr "Du kannst ohne Anmeldung an dem Quiz teilnehmen. Um Missbrauch vorzubeugen, wird für deinen Browser und dein Gerät ein sogenannter Fingerprint erzeugt, mit dem wir dich während deiner Teilnahme identifzieren können. Dem stimmst du durch deine Teilnahme zu." + +#. js-lingui-explicit-id +msgid "login-page.store-cookie-checkbox" +msgstr "Ich möchte dass meine Anmeldung für 30 Tage erhalten bleibt, auch wenn ich das Browserfenster schließe." #. js-lingui-explicit-id msgid "login-page.info-text" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index c1eaf26..b842e03 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1323,7 +1323,11 @@ msgstr "Participate without logging in" #. js-lingui-explicit-id msgid "login-page.temp-login-reminder" -msgstr "You can participate in the quiz without logging in. To prevent abuse, a so-called fingerprint is created for your browser and device, which allows us to identify you during your participation. By participating, you agree to this. To log out later, simply close your browser." +msgstr "You can participate in the quiz without logging in. To prevent abuse, a so-called fingerprint is created for your browser and device, which allows us to identify you during your participation. By participating, you agree to this." + +#. js-lingui-explicit-id +msgid "login-page.store-cookie-checkbox" +msgstr "I want my login to be stored for 30 days, even if I close the browser window." #. js-lingui-explicit-id msgid "login-page.info-text" diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index 93013f2..d02350f 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -123,6 +123,7 @@ export const QuestionEdit: React.FC = () => { // const students = mbQuiz.flatMap(q => maybe(q.quiz)).flatMap(q => maybe(q.students)); // const isStudent = mbUser.map(u => students.map(s => s.includes(u.user.uid)).orElse(false)).orElse(false); const userId: Id = mbUser.flatMap(u => maybe(u.user?.uid)).orElse(toId("")); + const isTemporary = mbUser.flatMap(u => maybe(u.user?.isTemporary)).orElse(false); // const teachers = mbQuiz.flatMap(q => maybe(q.quiz)).flatMap(q => maybe(q.teachers)); // const isQuizTeacher = mbUser.map(u => teachers.map(s => s.includes(u.user.uid)).orElse(false)).orElse(false); @@ -156,7 +157,7 @@ export const QuestionEdit: React.FC = () => { const aat: UserParticipation[] = keys(quiz?.quiz.studentParticipationSettings) .filter(k => !!quiz?.quiz.studentParticipationSettings[k as UserParticipation]) .map(k => k as UserParticipation); - setAllowedAuthorTypes(aat); + setAllowedAuthorTypes(isTemporary ? aat.filter(at => at !== "NAME") : aat); const aqt: QuestionType[] = keys(quiz?.quiz.allowedQuestionTypesSettings) .filter(k => !!quiz?.quiz.allowedQuestionTypesSettings[k as QuestionType]) diff --git a/packages/frontend/src/pages/QuizPage.tsx b/packages/frontend/src/pages/QuizPage.tsx index bf7b9e5..844d525 100644 --- a/packages/frontend/src/pages/QuizPage.tsx +++ b/packages/frontend/src/pages/QuizPage.tsx @@ -254,6 +254,7 @@ export const QuizPage: React.FC = () => { const questionId = currentQuestion?.uid ?? toId(""); const disableForStudent = localUser.map(allowed).orElse(true); + const isTemporary = localUser.flatMap(u => maybe(u.isTemporary)).orElse(false); const isQuizTeacher = teachers.includes(localUser.map(u => u.uid).orElse(toId(""))) || localUser.map(u => u.role).is(r => r === "ADMIN"); @@ -305,6 +306,19 @@ export const QuizPage: React.FC = () => { ); }; + let participationOptions = + keys(quizData.quiz.studentParticipationSettings) + .filter(k => !!quizData.quiz.studentParticipationSettings[k as UserParticipation]) + .map(k => k as UserParticipation); + if (isTemporary) { + participationOptions = participationOptions.filter(p => p !== "NAME"); + if (participationOptions.length === 0) { + // TODO: Fehler anzeigen. Der Nutzer kann an dem Quiz nicht teilnehmen. + return +

Dieses Quiz hat Realnamenzwang. Melde dich bitte ab und mit deinem Uniaccount an.

+
; + } + } return ( { // isStudent={!isQuizTeacher} isUserInTeachersList={isUserInTeachersList} userNames={[userName, userNickname ?? ""]} - participationOptions={keys(quizData.quiz.studentParticipationSettings) - .filter(k => !!quizData.quiz.studentParticipationSettings[k as UserParticipation]) - .map(k => k as UserParticipation)} + participationOptions={participationOptions} /> {!quizData.isPresentationModeActive ? ( diff --git a/packages/models/src/data/session.ts b/packages/models/src/data/session.ts index 8e38c90..b437d0e 100644 --- a/packages/models/src/data/session.ts +++ b/packages/models/src/data/session.ts @@ -2,6 +2,17 @@ import zod from "zod"; import { timestampSchema, uidSchema } from "./base"; import { userRoleSchema } from "./user"; +export const fingerprintSchema = zod.object({ + uid: uidSchema, // This is also the fingerprint string itself + created: timestampSchema, + updated: timestampSchema, + lastSeen: timestampSchema, + usageCount: zod.number().int(), + blocked: zod.boolean(), +}); + +export type Fingerprint = zod.infer; + export const sessionSchema = zod.object({ idToken: zod.string(), accessToken: zod.string(), @@ -14,6 +25,7 @@ export const sessionSchema = zod.object({ created: timestampSchema, updated: timestampSchema, fingerprint: zod.string().optional(), // Fingerprint, is set if this is a temporary account + persistentCookie: zod.boolean().optional() // Whether this is a temporary account that is not deleted when closing the browser but stored in a persistentcookie }); export type Session = zod.infer; diff --git a/packages/models/src/index.ts b/packages/models/src/index.ts index 95f2f67..01a6239 100644 --- a/packages/models/src/index.ts +++ b/packages/models/src/index.ts @@ -5,6 +5,7 @@ export * from "./data/statistics"; export * from "./data/comment"; export * from "./data/session"; export * from "./messages/sessionStore"; +export * from "./messages/fingerprintStore"; export * from "./messages/userStore"; export * from "./messages/commentActor"; export * from "./messages/questionActor"; diff --git a/packages/models/src/messages/fingerprintStore.ts b/packages/models/src/messages/fingerprintStore.ts new file mode 100644 index 0000000..d557324 --- /dev/null +++ b/packages/models/src/messages/fingerprintStore.ts @@ -0,0 +1,21 @@ +import { unionize, ofType, UnionOf } from "unionize"; +import { Fingerprint } from "../data/session"; +import { Id } from "../data/base"; + +export const FingerprintStoreMessages = unionize( + { + StoreFingerprint: ofType & { uid: Id }>(), // Store the session; also removed older sessions of the user + Block: ofType(), // Block a fingerprint + Unblock: ofType(), // Unblock a fingerprint + IncreaseCount: ofType(), // Increase usage count by one + GetMostRecent: {}, // Get the most recently seen fingerprints + }, + { tag: "FingerprintStoreMessages", value: "value" } +); + +export type FingerprintStoreMessage = UnionOf; + +export class FingerprintUpdateMessage { + public readonly tag = "FingerprintUpdateMessage" as const; + constructor(public readonly fp: Partial) {} +} From 4235aac1d590150498ebbfde05bcdb510d7e2180 Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Tue, 10 Dec 2024 18:35:58 +0100 Subject: [PATCH 14/51] Fingerprint-Administration und Anpassungen an den Berechtigungen. --- .../backend/src/actors/FingerprintStore.ts | 55 ++++++++---- packages/backend/src/actors/UserStore.ts | 4 +- .../backend/src/middlewares/authRoutes.ts | 60 ++++++++++++- packages/backend/src/utils.ts | 2 +- packages/frontend/src/Activate.tsx | 9 +- packages/frontend/src/Dashboard.tsx | 6 ++ packages/frontend/src/FingerprintPanel.tsx | 59 ++++++++++++ packages/frontend/src/actorUris.ts | 1 + .../frontend/src/actors/UserAdminActor.ts | 25 +++++- .../src/components/cards/FingerprintCard.tsx | 90 +++++++++++++++++++ .../layout/UserParticipationSelect.tsx | 4 + .../frontend/src/layout/HeaderSection.tsx | 2 +- packages/frontend/src/locales/de/messages.po | 22 +++++ packages/models/src/data/session.ts | 2 + .../models/src/messages/fingerprintStore.ts | 4 +- 15 files changed, 314 insertions(+), 31 deletions(-) create mode 100644 packages/frontend/src/FingerprintPanel.tsx create mode 100644 packages/frontend/src/components/cards/FingerprintCard.tsx diff --git a/packages/backend/src/actors/FingerprintStore.ts b/packages/backend/src/actors/FingerprintStore.ts index 92847a2..7f3c22c 100644 --- a/packages/backend/src/actors/FingerprintStore.ts +++ b/packages/backend/src/actors/FingerprintStore.ts @@ -1,8 +1,8 @@ import { Timestamp, Unit, toTimestamp, unit } from "itu-utils"; import { ActorRef, ActorSystem } from "ts-actors"; import { create } from "mutative"; -import { ActorUri, Fingerprint, FingerprintStoreMessage, FingerprintStoreMessages, FingerprintUpdateMessage, Id } from "@recapp/models"; -import { pick } from "rambda"; +import { ActorUri, Fingerprint, FingerprintStoreMessage, FingerprintStoreMessages, FingerprintUpdateMessage, Id, User, UserStoreMessage, UserStoreMessages } from "@recapp/models"; +import { identity, pick } from "rambda"; import { CollecionSubscription, SubscribableActor } from "./SubscribableActor"; type FingerprintStoreResult = Unit | Error | Fingerprint | boolean; @@ -43,27 +43,36 @@ export class FingerprintStore extends SubscribableActor { - const [clientUserRole] = await this.determineRole(from); + const [clientUserRole, clientUserId] = await this.determineRole(from); if (!["ADMIN", "SYSTEM"].includes(clientUserRole)) { return new Error(`Operation not allowed`); } const result = await FingerprintStoreMessages.match>(message, { - StoreFingerprint: async session => { + StoreFingerprint: async fingerprint => { this.state = await create(this.state, async draft => { - const currentSession = (await this.getEntity(session.uid)).orElse({} as Fingerprint); - session.updated = toTimestamp(); - const newSession = { ...currentSession, ...session }; - draft.cache.set(session.uid, newSession); - this.storeEntity(newSession); + const currentFingerprint = (await this.getEntity(fingerprint.uid)).orElse({} as Fingerprint); + fingerprint.updated = toTimestamp(); + const newFingerprint = { ...currentFingerprint, ...fingerprint }; + draft.cache.set(fingerprint.uid, newFingerprint); + console.debug("SToring new fingerprint", newFingerprint); + this.storeEntity(newFingerprint); }); return unit(); }, + Get: async id => { + const result = await this.getEntity(id); + const retVal = result.match(identity, () => new Error(`Unknown fingerprint id ${id}`)); + return Promise.resolve(retVal) + }, Block: async id => { const mbFingerprint = await this.getEntity(id) + const {uid} = await this.ask("actors://recapp-backend/UserStore", UserStoreMessages.GetByFingerprint(id)); return mbFingerprint.match( fp => { this.storeEntity({...fp, blocked: true}); this.updateSubscribers({...fp, blocked: true}) + if (uid) + this.send("actors://recapp-backend/UserStore", UserStoreMessages.Update({ uid: fp.uid, active: false })); return unit(); }, () => { @@ -73,10 +82,13 @@ export class FingerprintStore extends SubscribableActor { const mbFingerprint = await this.getEntity(id) + const {uid} = await this.ask("actors://recapp-backend/UserStore", UserStoreMessages.GetByFingerprint(id)); return mbFingerprint.match( fp => { this.storeEntity({...fp, blocked: false}); - this.updateSubscribers({...fp, blocked: true}) + this.updateSubscribers({...fp, blocked: false}) + if (uid) + this.send("actors://recapp-backend/UserStore", UserStoreMessages.Update({ uid: fp.uid, active: true })); return unit(); }, () => { @@ -84,16 +96,16 @@ export class FingerprintStore extends SubscribableActor { - const mbFingerprint = await this.getEntity(id) + IncreaseCount: async ({fingerprint, userUid, initialQuiz}) => { + const mbFingerprint = await this.getEntity(fingerprint) return mbFingerprint.match( fp => { - this.storeEntity({...fp, usageCount: fp.usageCount + 1}); - this.updateSubscribers({...fp, blocked: true}) + this.storeEntity({...fp, usageCount: fp.usageCount + 1, lastSeen: toTimestamp(), userUid, initialQuiz: initialQuiz ?? fp.initialQuiz}); + this.updateSubscribers({...fp, usageCount: fp.usageCount + 1, lastSeen: toTimestamp(), userUid, initialQuiz: initialQuiz ?? fp.initialQuiz}) return unit(); }, () => { - return new Error(`Unknown fingerprint id ${id}`); + return new Error(`Unknown fingerprint id ${fingerprint}`); } ) }, @@ -106,7 +118,18 @@ export class FingerprintStore extends SubscribableActor new Error(`Unknown message from ${from.name}`), + SubscribeToCollection: async () => { + this.state = create(this.state, draft => { + draft.lastSeen.set(from.name as ActorUri, toTimestamp()); + draft.collectionSubscribers.set(from.name as ActorUri, { + properties: [], + userId: clientUserId, + userRole: clientUserRole, + }); + }); + return unit(); + }, + default: async () => new Error(`Unknown message from ${from.name}: ${JSON.stringify(message, undefined, 2)}`), }); return result; } diff --git a/packages/backend/src/actors/UserStore.ts b/packages/backend/src/actors/UserStore.ts index ea9e16f..066503f 100644 --- a/packages/backend/src/actors/UserStore.ts +++ b/packages/backend/src/actors/UserStore.ts @@ -177,9 +177,9 @@ export class UserStore extends SubscribableActor(this.collectionName).find({}).toArray(); users.forEach(user => { const { _id, quizUsage, ...rest } = user; - if (clientUserRole === "SYSTEM" || !rest.isTemporary) { + //if (clientUserRole === "SYSTEM" || !rest.isTemporary) { this.send(from, new UserUpdateMessage(rest)); - } + //} }); return unit(); }, diff --git a/packages/backend/src/middlewares/authRoutes.ts b/packages/backend/src/middlewares/authRoutes.ts index 5a3db9d..1d2d54a 100644 --- a/packages/backend/src/middlewares/authRoutes.ts +++ b/packages/backend/src/middlewares/authRoutes.ts @@ -5,7 +5,7 @@ import Container from "typedi"; import koa from "koa"; import { ActorSystem } from "ts-actors"; import { calculateFingerprint, createActorUri, createTempJwt } from "../utils"; -import { Id, Session, SessionStoreMessages, User, UserRole, UserStoreMessages } from "@recapp/models"; +import { Fingerprint, FingerprintStoreMessages, Id, Session, SessionStoreMessages, User, UserRole, UserStoreMessages } from "@recapp/models"; import { toTimestamp } from "itu-utils"; import { DateTime } from "luxon"; import { maybe } from "tsmonads"; @@ -61,6 +61,49 @@ export const authTempAccount = async (ctx: koa.Context): Promise => { // Prüfen ob gesperrt const system = Container.get("actor-system"); const userStore = createActorUri("UserStore"); + const fpStore = createActorUri("FingerprintStore"); + const uid = v4() as Id; + + try { + let fpData: Fingerprint | Error = await system.ask(fpStore, FingerprintStoreMessages.Get(fingerprint as Id)); + console.log("New fingerprint", fingerprint, fpData); + if (fpData instanceof Error) { + console.debug("A new fingerprint has been found", fingerprint); + const fp: Fingerprint = { + uid: fingerprint as Id, + created: toTimestamp(), + updated: toTimestamp(), + lastSeen: toTimestamp(), + usageCount: 1, + blocked: false, + userUid: uid, + initialQuiz: quiz && quiz !== "false" ? quiz as Id : undefined, + }; + await system.send(fpStore, FingerprintStoreMessages.StoreFingerprint(fp)); + fpData = fp; + } + await system.send(fpStore, FingerprintStoreMessages.IncreaseCount({fingerprint: fingerprint as Id, userUid: uid as Id, initialQuiz: quiz && quiz !== "false" ? quiz as Id : undefined})); + if (fpData.blocked) { + console.debug("Fingerprint was blocked", fingerprint); + ctx.redirect((process.env.FRONTEND_URI ?? "http://localhost:5173") + "?error=userdeactivated"); + return; + } + } catch (e) { + console.error(e); + console.debug("A new fingerprint has been found", fingerprint); + const fp: Fingerprint = { + uid: fingerprint as Id, + created: toTimestamp(), + updated: toTimestamp(), + lastSeen: toTimestamp(), + usageCount: 1, + blocked: false, + userUid: uid, + initialQuiz: quiz && quiz !== "false" ? quiz as Id : undefined, + }; + await system.send(fpStore, FingerprintStoreMessages.StoreFingerprint(fp)); + await system.send(fpStore, FingerprintStoreMessages.IncreaseCount({fingerprint: fingerprint as Id, userUid: uid as Id, initialQuiz: quiz && quiz !== "false" ? quiz as Id : undefined})); + } try { const existingUser: User | Error = await system.ask(userStore, UserStoreMessages.GetByFingerprint(fingerprint)); if (existingUser instanceof Error) { @@ -73,7 +116,6 @@ export const authTempAccount = async (ctx: koa.Context): Promise => { console.error(e); } // Wenn nicht, dann Token, temporären User und Session anlegen - const uid = v4() as Id; const token = createTempJwt(uid, fingerprint); const decoded = jwt.decode(token) as jwt.JwtPayload; const sessionStore = createActorUri("SessionStore"); @@ -287,6 +329,19 @@ export const authRefresh = async (ctx: koa.Context): Promise => { } // If this is a temporary account, just return if (session.fingerprint) { + const fpStore = createActorUri("FingerprintStore"); + try { + let fpData: Fingerprint = await system.ask(fpStore, FingerprintStoreMessages.Get(session.fingerprint as Id)); + await system.ask(fpStore, FingerprintStoreMessages.IncreaseCount({fingerprint: session.fingerprint as Id, userUid: session.uid, initialQuiz: undefined})); + if (fpData.blocked) { + system.send(sessionStore, SessionStoreMessages.RemoveSession(sub as Id)); + ctx.set("Set-Cookie", `bearer=; path=/`); + ctx.throw(401, "Token renewal failure"); + return; + } + } catch (e) { + console.error(e); + } const token = createTempJwt(session.uid, session.fingerprint); const thirtyDaysFromNow = new Date(); thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30); @@ -294,6 +349,7 @@ export const authRefresh = async (ctx: koa.Context): Promise => { ctx.body = "O.K."; return; } + try { const newTokenSet = await client.refresh(session.refreshToken); const decoded = jwt.decode(newTokenSet.id_token ?? "") as jwt.JwtPayload; diff --git a/packages/backend/src/utils.ts b/packages/backend/src/utils.ts index 64f5fcc..d86de78 100644 --- a/packages/backend/src/utils.ts +++ b/packages/backend/src/utils.ts @@ -11,7 +11,7 @@ import crypto from "crypto"; export const systemName = "recapp-backend"; -export const createActorUri = (actorName: "SessionStore" | "UserStore" | "QuizActor" | "ErrorActor"): ActorUri => { +export const createActorUri = (actorName: "SessionStore" | "UserStore" | "QuizActor" | "ErrorActor" | "FingerprintStore"): ActorUri => { return `actors://${join(systemName, actorName)}` as ActorUri; }; diff --git a/packages/frontend/src/Activate.tsx b/packages/frontend/src/Activate.tsx index 05fe42b..f89aa9c 100644 --- a/packages/frontend/src/Activate.tsx +++ b/packages/frontend/src/Activate.tsx @@ -34,16 +34,17 @@ export const Activate: React.FC = () => { - - - - + setPersistentCookie(event.target.checked)} /> + +   + + diff --git a/packages/frontend/src/Dashboard.tsx b/packages/frontend/src/Dashboard.tsx index 1bacf50..f190763 100644 --- a/packages/frontend/src/Dashboard.tsx +++ b/packages/frontend/src/Dashboard.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from "react"; import { UserAdminPanel } from "./UserAdminPanel"; +import { FingerprintPanel } from "./FingerprintPanel"; import { Tab, Tabs } from "react-bootstrap"; import { i18n } from "@lingui/core"; import { QuizzesPanel } from "./components/quizzes-panel/QuizzesPanel"; @@ -49,6 +50,11 @@ export const Dashboard: React.FC = () => { )} + {isAdmin && ( + + + + )} ); diff --git a/packages/frontend/src/FingerprintPanel.tsx b/packages/frontend/src/FingerprintPanel.tsx new file mode 100644 index 0000000..7d9c599 --- /dev/null +++ b/packages/frontend/src/FingerprintPanel.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import { Fingerprint } from "@recapp/models"; +import { useStatefulActor } from "ts-actors-react"; +import { i18n } from "@lingui/core"; +import { Trans } from "@lingui/react"; +import { maybe } from "tsmonads"; + +import InputGroup from "react-bootstrap/InputGroup"; +import Form from "react-bootstrap/Form"; +import { Funnel } from "react-bootstrap-icons"; +import { FingerprintCard } from "./components/cards/FingerprintCard"; +import { TooltipWrapper } from "./components/TooltipWrapper"; + +export const FingerprintPanel: React.FC = () => { + const [fingerprintList] = useStatefulActor<{ fingerprints: Fingerprint[] }>("UserAdmin"); + const [filter, setFilter] = useState(""); + const fingerprints = fingerprintList + .flatMap(fpl => maybe(fpl.fingerprints)) + .map(fpl => + fpl + .filter( + (fp: Fingerprint) => + fp.uid.toLocaleLowerCase().includes(filter) + ) + .slice(0, 50) + ); + return ( +
+

+ +

+
+ + + + + + + setFilter(event.target.value.toLocaleLowerCase())} + /> + +
+
+ {fingerprints.orElse([]).map((fp: Fingerprint) => ( + + ))} + + {/* to fill the empty space so that when a single card is displayed will not take the full width */} +
+
+
+
+
+ ); +}; diff --git a/packages/frontend/src/actorUris.ts b/packages/frontend/src/actorUris.ts index 30e8c3f..b4397ca 100644 --- a/packages/frontend/src/actorUris.ts +++ b/packages/frontend/src/actorUris.ts @@ -2,6 +2,7 @@ import { ActorUri } from "@recapp/models"; export const actorUris: Record = { UserStore: "actors://recapp-backend/UserStore" as ActorUri, + FingerprintStore: "actors://recapp-backend/FingerprintStore" as ActorUri, SessionStore: "actors://recapp-backend/SessionStore" as ActorUri, QuizActor: "actors://recapp-backend/QuizActor" as ActorUri, CommentActorPrefix: "actors://recapp-backend/QuizActor/Comment_" as ActorUri, diff --git a/packages/frontend/src/actors/UserAdminActor.ts b/packages/frontend/src/actors/UserAdminActor.ts index 9bfb9e0..e75e9e3 100644 --- a/packages/frontend/src/actors/UserAdminActor.ts +++ b/packages/frontend/src/actors/UserAdminActor.ts @@ -1,11 +1,11 @@ import { ActorRef, ActorSystem } from "ts-actors"; import { StatefulActor } from "ts-actors-react"; -import { User, UserStoreMessages, UserUpdateMessage } from "@recapp/models"; +import { Fingerprint, FingerprintStoreMessages, FingerprintUpdateMessage, User, UserStoreMessages, UserUpdateMessage } from "@recapp/models"; -export class UserAdminActor extends StatefulActor { +export class UserAdminActor extends StatefulActor { constructor(name: string, system: ActorSystem) { super(name, system); - this.state = { users: [] }; + this.state = { users: [], fingerprints: [] }; } override send(to: string | ActorRef, message: S): void { @@ -21,17 +21,34 @@ export class UserAdminActor extends StatefulActor { UserStoreMessages.SubscribeToCollection(["uid", "username", "role", "active", "lastlogin", "nickname"]) ); } + const fpResult: User = await this.ask("actors://recapp-backend/FingerprintStore", FingerprintStoreMessages.GetMostRecent()); + if (this.state.fingerprints.length === 0 && fpResult) { + this.send( + "actors://recapp-backend/FingerprintStore", + FingerprintStoreMessages.SubscribeToCollection() + ); + } } - async receive(_from: ActorRef, message: UserUpdateMessage): Promise { + async receive(_from: ActorRef, message: UserUpdateMessage | FingerprintUpdateMessage): Promise { console.log("USERADMIN", _from.name, message); if (message.tag == "UserUpdateMessage") { + if (message.user.isTemporary) { + return true; + } this.updateState(draft => { draft.users = draft.users.filter(u => u.uid != message.user.uid); draft.users.push(message.user as User); draft.users.sort((a, b) => a.uid.localeCompare(b.uid)); }); } + if (message.tag == "FingerprintUpdateMessage") { + this.updateState(draft => { + draft.fingerprints = draft.fingerprints.filter(u => u.uid != message.fp.uid); + draft.fingerprints.push(message.fp as Fingerprint); + draft.fingerprints.sort((a, b) => a.lastSeen.value - b.lastSeen.value); + }); + } return true; } } diff --git a/packages/frontend/src/components/cards/FingerprintCard.tsx b/packages/frontend/src/components/cards/FingerprintCard.tsx new file mode 100644 index 0000000..f90eaf3 --- /dev/null +++ b/packages/frontend/src/components/cards/FingerprintCard.tsx @@ -0,0 +1,90 @@ +import { Fingerprint, FingerprintStoreMessages, Id, Quiz, User } from "@recapp/models"; +import { useStatefulActor } from "ts-actors-react"; +import { i18n } from "@lingui/core"; +import { fromTimestamp, toTimestamp } from "itu-utils"; + +import Card from "react-bootstrap/Card"; +import { CheckCircleFill, CircleFill } from "react-bootstrap-icons"; +import { actorUris } from "../../actorUris"; +import { maybe } from "tsmonads"; + +interface Props { + fingerprint: Fingerprint; +} + +export const FingerprintCard = ({ fingerprint }: Props) => { + const [, actor] = useStatefulActor<{ users: User[] }>("UserAdmin"); + const [quizData] = useStatefulActor<{ + quizzes: Map>; + }>("LocalUser"); + + const toggleActivate = () => { + actor.forEach(a => + a.send(actorUris.FingerprintStore, fingerprint.blocked ? FingerprintStoreMessages.Unblock(fingerprint.uid) : FingerprintStoreMessages.Block(fingerprint.uid)) + ); + }; + + const userQuizzes: Array<{title: string, uid: Id}> = quizData.flatMap(q => maybe(q.quizzes)).map(ql => Array.from(ql.values()).filter(q => q.students?.includes(fingerprint.userUid)).map(q => ({title: q.title ?? "", uid: q.uid ?? "" as Id}))).orElse([]); + + console.log("Fingerprint:", fingerprint); + + return ( + <> +
+
+ {i18n._({ + id: "fingerprint.card-last-seen: {date}", + values: { + date: fromTimestamp(fingerprint.lastSeen ?? toTimestamp()).toLocaleString({ + dateStyle: "medium", + timeStyle: "medium", + }), + }, + })} +
+ + +

{fingerprint.uid}

+
+ + +
+ + +
+
+ Auth count: {fingerprint.usageCount} +
+
+ {userQuizzes.map(q => { + if (q.uid === fingerprint.initialQuiz) { + return ( + <>{q.title}
+ ); + } + return ( + <>{q.title}
+ ); + })} +
+
+
+
+ + ); +}; + +const BlockedIndicator = (props: { blocked: boolean; onClick: () => void }) => { + return ( +
+ {props.blocked ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/packages/frontend/src/components/layout/UserParticipationSelect.tsx b/packages/frontend/src/components/layout/UserParticipationSelect.tsx index 83f0d1d..8541390 100644 --- a/packages/frontend/src/components/layout/UserParticipationSelect.tsx +++ b/packages/frontend/src/components/layout/UserParticipationSelect.tsx @@ -31,6 +31,7 @@ const storeParticipationValue = (value: UserParticipation) => { interface Props { label?: string; + temporary: boolean; } export const UserParticipationSelect = (props: Props) => { @@ -58,6 +59,9 @@ export const UserParticipationSelect = (props: Props) => { label: i18n._("participation-select-option.name") }, }; + if (props.temporary) { + delete (userParticipationOptions as any).NAME; + } useEffect(() => { if (storedValue) { diff --git a/packages/frontend/src/layout/HeaderSection.tsx b/packages/frontend/src/layout/HeaderSection.tsx index 29458aa..8884bbe 100644 --- a/packages/frontend/src/layout/HeaderSection.tsx +++ b/packages/frontend/src/layout/HeaderSection.tsx @@ -129,7 +129,7 @@ export const HeaderSection: React.FC = () => { {/* */} - + {/* */} diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 8982904..d8c7b2b 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1336,3 +1336,25 @@ msgstr "Login-Fehler. Account deaktiviert." #. js-lingui-explicit-id msgid "login-page.account-deactivated-message" msgstr "Ihr Account wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator." + +#. js-lingui-explicit-id +msgid "fingerprint.card-last-seen: {date}" +msgstr "Letzte Tokenaktualisierung: {date}" + +#. js-lingui-explicit-id +msgid "fingerprint-panel.search-text" +msgstr "Fingerprint suchen" + +#. js-lingui-explicit-id +msgid "fingerprint-panel.button-tooltip.filter" +msgstr "Teile des Fingerprints eingeben um zu filtern" + +#. js-lingui-explicit-id +msgid "fingerprint-panel.title" +msgstr "Fingerprint Verwaltung (Temporäre Accounts)" + +#. js-lingui-explicit-id +msgid "dashboard-tab-label-fingerprints" +msgstr "Temporäre Accounts" + + diff --git a/packages/models/src/data/session.ts b/packages/models/src/data/session.ts index b437d0e..32b3568 100644 --- a/packages/models/src/data/session.ts +++ b/packages/models/src/data/session.ts @@ -9,6 +9,8 @@ export const fingerprintSchema = zod.object({ lastSeen: timestampSchema, usageCount: zod.number().int(), blocked: zod.boolean(), + userUid: uidSchema, + initialQuiz: uidSchema.optional() }); export type Fingerprint = zod.infer; diff --git a/packages/models/src/messages/fingerprintStore.ts b/packages/models/src/messages/fingerprintStore.ts index d557324..761a7e0 100644 --- a/packages/models/src/messages/fingerprintStore.ts +++ b/packages/models/src/messages/fingerprintStore.ts @@ -5,10 +5,12 @@ import { Id } from "../data/base"; export const FingerprintStoreMessages = unionize( { StoreFingerprint: ofType & { uid: Id }>(), // Store the session; also removed older sessions of the user + Get: ofType(), // Get fingerprint info Block: ofType(), // Block a fingerprint Unblock: ofType(), // Unblock a fingerprint - IncreaseCount: ofType(), // Increase usage count by one + IncreaseCount: ofType<{fingerprint: Id, userUid: Id, initialQuiz: Id | undefined}>(), // Increase usage count by one GetMostRecent: {}, // Get the most recently seen fingerprints + SubscribeToCollection: {} }, { tag: "FingerprintStoreMessages", value: "value" } ); From 00a6d392b97301f33c648ad4393dcdac4729f790 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 09:19:50 +0100 Subject: [PATCH 15/51] Changed name of preview button to Participant and Teacher view. --- packages/frontend/src/locales/de/messages.po | 4 ++-- packages/frontend/src/locales/en/messages.po | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 150e943..9f2f9c2 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1307,9 +1307,9 @@ msgstr "Teilnehmende können Fragen stellen" #. js-lingui-explicit-id msgid "quiz-button-label-end-preview" -msgstr "Vorschau beenden" +msgstr "Lehrpersonenansicht" #. js-lingui-explicit-id msgid "quiz-button-label-start-preview" -msgstr "Vorschau starten" +msgstr "Teilnehmendenansicht" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index eb3e37c..7ed116f 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1307,8 +1307,8 @@ msgstr "Allow participants to create/edit questions" #. js-lingui-explicit-id msgid "quiz-button-label-end-preview" -msgstr "End preview" +msgstr "Teacher view" #. js-lingui-explicit-id msgid "quiz-button-label-start-preview" -msgstr "Start preview" +msgstr "Participant view" From 56c0ad3fa02fc29c39024ba68058ef9b38f9517d Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 09:30:46 +0100 Subject: [PATCH 16/51] Added the tooltip for the preview button --- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/locales/en/messages.po | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 9f2f9c2..f02f515 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1313,3 +1313,7 @@ msgstr "Lehrpersonenansicht" msgid "quiz-button-label-start-preview" msgstr "Teilnehmendenansicht" +#. js-lingui-explicit-id +msgid "quiz-button-tooltip-preview" +msgstr "Achtung: In der Teilnehmeransicht wird das Quiz automatisch gestartet. Es wird nur gestoppt, wenn niemand mehr teilnimmt." + diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 7ed116f..5f378d8 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1312,3 +1312,7 @@ msgstr "Teacher view" #. js-lingui-explicit-id msgid "quiz-button-label-start-preview" msgstr "Participant view" + +#. js-lingui-explicit-id +msgid "quiz-button-tooltip-preview" +msgstr "Attention: The Participant view will automatically start the quiz. It will only stop if no one is taking part." From 4b2473563cd64edaec4392b19c895c8da5846d5c Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 09:36:41 +0100 Subject: [PATCH 17/51] Changed the preview button to a button with tooltip --- packages/frontend/src/components/quiz-tabs/QuizButtons.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizButtons.tsx b/packages/frontend/src/components/quiz-tabs/QuizButtons.tsx index 0405c23..36b7bfe 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizButtons.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizButtons.tsx @@ -313,17 +313,18 @@ export const QuizButtons = (props: {
{props.isQuizTeacher && ( - + )}
From 50c74e6faf82ca79896358f821d689f9e117b8fe Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 10:28:08 +0100 Subject: [PATCH 18/51] Added warning message when new questions are disabled because participation is disabled --- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/locales/en/messages.po | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 150e943..6b1ece1 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -81,6 +81,10 @@ msgstr "Teilnehmende können Statistiken einsehen" msgid "quiz-data-tab.alert-message.create-new-question-is-disabled" msgstr "Die Schaltfläche 'Neue Frage erstellen' ist deaktiviert." +#. js-lingui-explicit-id +msgid "quiz-data-tab.alert-message.participation-is-disabled" +msgstr "Die Schaltfläche 'Neue Frage erstellen' ist deaktiviert." + #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:236 msgid "quiz-questions-tab-new-question-button.button-tooltip.create-question-disabled" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index eb3e37c..9335e46 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -81,6 +81,10 @@ msgstr "Participants can view statistics" msgid "quiz-data-tab.alert-message.create-new-question-is-disabled" msgstr "The 'New question' button is disabled" +#. js-lingui-explicit-id +msgid "quiz-data-tab.alert-message.participation-is-disabled" +msgstr "The 'New question' button is disabled" + #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:236 msgid "quiz-questions-tab-new-question-button.button-tooltip.create-question-disabled" From 923605a48755ca4c493feb1b2c1e7e9f33212c84 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 10:29:01 +0100 Subject: [PATCH 19/51] Added isParticipationDisabled helper function --- packages/frontend/src/utils.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/frontend/src/utils.ts b/packages/frontend/src/utils.ts index 7516b9b..a4edf76 100644 --- a/packages/frontend/src/utils.ts +++ b/packages/frontend/src/utils.ts @@ -77,6 +77,14 @@ export const checkIsCreatingQuestionDisabled = (allowedQuestionTypesSettings: Qu return isCreatingQuestionEnabled; }; +export const checkIsParticipationDisabled = (studentParticipationSettings: Quiz["studentParticipationSettings"]) => { + const isParticipationEnabled = Object.values(studentParticipationSettings).every(value => { + return !value; + }); + + return isParticipationEnabled; +}; + export const downloadFile = async (filename: string)=> { return await axios .get(`${import.meta.env.VITE_BACKEND_URI}/download/${filename}`, { From 92577c5d83460d85c3741caf68509af2b699791c Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Wed, 11 Dec 2024 10:33:30 +0100 Subject: [PATCH 20/51] Bei Fragen von Temps den Fingerprint im Tooltip anzeigen. --- packages/backend/src/actors/QuizActor.ts | 1 + packages/backend/src/middlewares/authRoutes.ts | 1 + packages/frontend/src/actors/CurrentQuizActor.ts | 1 + .../frontend/src/components/cards/QuestionCard.tsx | 11 ++++++++--- packages/models/src/data/quiz.ts | 1 + packages/models/src/data/user.ts | 1 + 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/actors/QuizActor.ts b/packages/backend/src/actors/QuizActor.ts index 861a232..f7a3636 100644 --- a/packages/backend/src/actors/QuizActor.ts +++ b/packages/backend/src/actors/QuizActor.ts @@ -452,6 +452,7 @@ export class QuizActor extends SubscribableActor => { active: true, quizUsage: new Map(), isTemporary: true, + fingerprint, initialQuiz: quiz && quiz !== "false" ? quiz : undefined, }) ); diff --git a/packages/frontend/src/actors/CurrentQuizActor.ts b/packages/frontend/src/actors/CurrentQuizActor.ts index 63acc2e..e438e84 100644 --- a/packages/frontend/src/actors/CurrentQuizActor.ts +++ b/packages/frontend/src/actors/CurrentQuizActor.ts @@ -565,6 +565,7 @@ export class CurrentQuizActor extends StatefulActor {
- - {i18n._("authored-by", { author: props.question.authorName })} - + { props.question.authorFingerprint ? + + {i18n._("authored-by", { author: props.question.authorName })} + + : + {i18n._("authored-by", { author: props.question.authorName })} + } {props.question.type} diff --git a/packages/models/src/data/quiz.ts b/packages/models/src/data/quiz.ts index c1306ff..c64cd46 100644 --- a/packages/models/src/data/quiz.ts +++ b/packages/models/src/data/quiz.ts @@ -19,6 +19,7 @@ export const questionSchema = zod text: zod.string(), // Question text type: questionTypesSchema, authorId: uidSchema, // Author id + authorFingerprint: zod.string().optional(), // Author id authorName: zod.string().optional(), // Display name of the author (may also be a nickname or ANONYMOUS) quiz: uidSchema, // Quiz the question belongs hint: zod.string().optional(), // Optional explanatory text/hint diff --git a/packages/models/src/data/user.ts b/packages/models/src/data/user.ts index 5266fad..079609d 100644 --- a/packages/models/src/data/user.ts +++ b/packages/models/src/data/user.ts @@ -24,6 +24,7 @@ export const userSchema = zod active: zod.boolean(), // Whether the user can login quizUsage: zod.map(uidSchema, quizUsageType), // How the user decided to participate in each individual quiz isTemporary: zod.boolean().optional().default(false), // Is this a temporary account + fingerprint: zod.string().optional(), // Fingerprint of a temp user for authentication purposes initialQuiz: zod.string().optional(), // Initial quiz, if any (will be set if the user logged in or was created with a link) }) .merge(idEntitySchema); From bfa293dcf9ccf43c2ccc93de8e78f820cf57673f Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Wed, 11 Dec 2024 10:42:07 +0100 Subject: [PATCH 21/51] Version bump --- packages/frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 56982e6..62aa622 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -1,7 +1,7 @@ { "name": "@recapp/frontend", "private": true, - "version": "1.5.6", + "version": "1.6.0", "type": "module", "scripts": { "dev": "vite", From 5780dd32a3351d7cd0588d6c71b151324f6cc9fa Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 10:43:43 +0100 Subject: [PATCH 22/51] Added isParticipationDisabled check and warning to quit-student-participation --- .../src/components/quiz-tabs/QuizDataTab.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx index cd2daa9..468109f 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx @@ -19,7 +19,7 @@ import axios from "axios"; import { QuizExportModal } from "../modals/QuizExportModal"; import { ButtonWithTooltip } from "../ButtonWithTooltip"; import { ShareQuizModal } from "../modals/ShareQuizModal"; -import { checkIsCreatingQuestionDisabled, debounce } from "../../utils"; +import { checkIsCreatingQuestionDisabled, checkIsParticipationDisabled, debounce } from "../../utils"; import { CharacterTracker } from "../CharacterTracker"; import { DESCRIPTION_MAX_CHARACTERS, TITLE_MAX_CHARACTERS, TITLE_MIN_CHARACTERS } from "../../constants/constants"; import { useCurrentQuiz } from "../../hooks/state-actor/useCurrentQuiz"; @@ -108,6 +108,7 @@ export const QuizDataTab: React.FC = props => { const isTitleAndDescriptionDisabled = props.disableForStudent || disabledByMode; const isCreatingQuestionDisabled = checkIsCreatingQuestionDisabled(quiz.allowedQuestionTypesSettings); + const isParticipationDisabled = checkIsParticipationDisabled(quizData.quiz.studentParticipationSettings); return (
@@ -276,6 +277,18 @@ export const QuizDataTab: React.FC = props => { + {isParticipationDisabled ? ( + +
+ +
+ + + {i18n._("quiz-data-tab.alert-message.participation-is-disabled")} + +
+ ) : null} + Date: Wed, 11 Dec 2024 10:46:11 +0100 Subject: [PATCH 23/51] Fixed typo --- packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx index 468109f..3080a1e 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx @@ -108,7 +108,7 @@ export const QuizDataTab: React.FC = props => { const isTitleAndDescriptionDisabled = props.disableForStudent || disabledByMode; const isCreatingQuestionDisabled = checkIsCreatingQuestionDisabled(quiz.allowedQuestionTypesSettings); - const isParticipationDisabled = checkIsParticipationDisabled(quizData.quiz.studentParticipationSettings); + const isParticipationDisabled = checkIsParticipationDisabled(quiz.studentParticipationSettings); return ( From 43d345d06cde6ad1cfbb5cfc299f2e00ae0ef23a Mon Sep 17 00:00:00 2001 From: Hendrik Belitz Date: Wed, 11 Dec 2024 13:12:56 +0100 Subject: [PATCH 24/51] Fix: Retain quiz and question id's via URI queries to restore state on hard reload of page. --- .../src/components/quiz-tabs/QuestionsTab.tsx | 3 ++- packages/frontend/src/pages/QuestionEdit.tsx | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuestionsTab.tsx b/packages/frontend/src/components/quiz-tabs/QuestionsTab.tsx index aa318d7..41b0bd1 100644 --- a/packages/frontend/src/components/quiz-tabs/QuestionsTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuestionsTab.tsx @@ -133,7 +133,7 @@ export const QuestionsTab: React.FC<{ } else { nav( { pathname: "/Dashboard/Question" }, - { state: { quizId: uid, group, write: writeAccess ? "true" : undefined } } + { state: { questionId: uid, quiz: quizData.quiz.uid, group, write: writeAccess ? "true" : undefined } } ); } }; @@ -282,6 +282,7 @@ export const QuestionsTab: React.FC<{ state: { // group: questionGroup.name, write: writeAccess ? "true" : undefined, + quiz: quizData.quiz.uid }, } ); diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index 1b831e2..fb6ba66 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -55,7 +55,7 @@ const sortComments = (a: Comment, b: Comment) => { export const QuestionEdit: React.FC = () => { const { state } = useLocation(); - const questionId = state?.quizId ?? ""; + const questionId = state?.questionId ?? ""; const [currentQuestionId, setCurrentQuestionId] = useState(questionId); const formerGroup = state?.group ?? ""; const writeAccess = state?.write === "true"; @@ -87,6 +87,11 @@ export const QuestionEdit: React.FC = () => { useEffect(() => { if (deleted) setShowError("quiz-error-quiz-deleted"); }, [deleted]); + useEffect(() => { + if (state.quiz && (mbQuiz.isEmpty() || mbQuiz.map(q => keys(q.quiz).length === 0))) { + tryQuizActor.forEach(a => a.send(a, CurrentQuizMessages.SetQuiz(state.quiz as Id))); + } + }, [state.quiz, mbQuiz]); const [defaultQuestion, setDefaultQuestion] = useState( { @@ -133,8 +138,10 @@ export const QuestionEdit: React.FC = () => { const currentQuestionIndex = questionsIds.findIndex(x => x === currentQuestionId); const isLastQuestion = currentQuestionIndex >= questionsIds.length - 1; - const isUserInTeachersList = quiz && userId ? isInTeachersList(quiz.quiz, userId) : false; - const isUserInStudentsList = quiz && userId ? isInStudentList(quiz.quiz, userId) : true; + console.log("LOCATION state", state, "QUIZ", quiz); + + const isUserInTeachersList = quiz?.quiz && keys(quiz?.quiz).length > 0 && userId ? isInTeachersList(quiz.quiz, userId) : false; + const isUserInStudentsList = quiz?.quiz && keys(quiz?.quiz).length > 0 && userId ? isInStudentList(quiz.quiz, userId) : true; const isStudentCommentsAllowed = q?.studentComments; const showCommentSection = isUserInTeachersList || (isQuizStateStarted && isStudentCommentsAllowed); @@ -948,7 +955,7 @@ export const QuestionEdit: React.FC = () => {
{question.type === "SINGLE" && } - {question.type === "MULTIPLE" && } + {question.type === "MULTIPLE" && }
{/* {isQuizTeacher && !shuffleAnswers ? ( */} {isActivateReorderAnswersVisible ? ( From a59bbac7bb5c9f72b7a63339d5bc6ee018aef9c0 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 13:37:04 +0100 Subject: [PATCH 25/51] Updated tooltip text for preview button --- packages/frontend/src/locales/de/messages.po | 2 +- packages/frontend/src/locales/en/messages.po | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 3d45a09..24f3e11 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1315,7 +1315,7 @@ msgstr "Teilnehmendenansicht" #. js-lingui-explicit-id msgid "quiz-button-tooltip-preview" -msgstr "Achtung: In der Teilnehmeransicht wird das Quiz automatisch gestartet. Es wird nur gestoppt, wenn niemand mehr teilnimmt." +msgstr "Startet das Quiz in der Teilnehmeransicht. Das Quiz stoppt, wenn alle beigetretenen Lehrer diesen Modus verlassen." #. js-lingui-explicit-id msgid "login-page.temporary-account-button" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 4436657..0f1a397 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1315,7 +1315,7 @@ msgstr "Participant view" #. js-lingui-explicit-id msgid "quiz-button-tooltip-preview" -msgstr "Attention: The Participant view will automatically start the quiz. It will only stop if no one is taking part." +msgstr "Starts quiz in participant view. Quiz stops when all joined teachers exit this mode." #. js-lingui-explicit-id msgid "login-page.temporary-account-button" From 7b67b66cd2655f7bc269b854c84b865c49d0afc1 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 11 Dec 2024 14:26:46 +0100 Subject: [PATCH 26/51] updated warning message for participation disabled --- packages/frontend/src/locales/de/messages.po | 2 +- packages/frontend/src/locales/en/messages.po | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 6b1ece1..325d522 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -83,7 +83,7 @@ msgstr "Die Schaltfläche 'Neue Frage erstellen' ist deaktiviert." #. js-lingui-explicit-id msgid "quiz-data-tab.alert-message.participation-is-disabled" -msgstr "Die Schaltfläche 'Neue Frage erstellen' ist deaktiviert." +msgstr "Fragen- und Kommentarerstellung sind für Teilnehmende deaktiviert." #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:236 diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 9335e46..bbf0b3d 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -83,7 +83,7 @@ msgstr "The 'New question' button is disabled" #. js-lingui-explicit-id msgid "quiz-data-tab.alert-message.participation-is-disabled" -msgstr "The 'New question' button is disabled" +msgstr "Submission of questions and comments is disabled for participants." #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:236 From 16a34ff9309d94087b154241b0d1c58ecf7d1026 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Fri, 13 Dec 2024 09:36:57 +0100 Subject: [PATCH 27/51] Commented warning out until functionality is implemented --- packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx index 3080a1e..f444672 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizDataTab.tsx @@ -277,7 +277,9 @@ export const QuizDataTab: React.FC = props => { - {isParticipationDisabled ? ( + + {/* // remove comment when functionality is implemented + {isParticipationDisabled ? (
@@ -287,7 +289,7 @@ export const QuizDataTab: React.FC = props => { {i18n._("quiz-data-tab.alert-message.participation-is-disabled")} - ) : null} + ) : null} */} Date: Sat, 14 Dec 2024 15:37:30 +0100 Subject: [PATCH 28/51] Added msgids for question and new question for breadcrumb navigation --- packages/frontend/src/locales/de/messages.po | 6 ++++++ packages/frontend/src/locales/en/messages.po | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 3bcf264..8e66278 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1369,4 +1369,10 @@ msgstr "Fingerprint Verwaltung (Temporäre Accounts)" msgid "dashboard-tab-label-fingerprints" msgstr "Temporäre Accounts" +#. js-lingui-explicit-id +msgid "new-question" +msgstr "Neue Frage" +#. js-lingui-explicit-id +msgid "question" +msgstr "Frage" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index bb0a6c4..d30ae83 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1352,3 +1352,11 @@ msgstr "Login error. Account deactivated." #. js-lingui-explicit-id msgid "login-page.account-deactivated-message" msgstr "Your account was deactivated. Please contact the administrator." + +#. js-lingui-explicit-id +msgid "new-question" +msgstr "New question" + +#. js-lingui-explicit-id +msgid "question" +msgstr "Question" \ No newline at end of file From 3108528d88b24aa0743ccb04c252e53563a7cfb1 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Sat, 14 Dec 2024 15:39:32 +0100 Subject: [PATCH 29/51] Updated breadcrumb to have a translation for question and new question --- packages/frontend/src/pages/QuestionEdit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/QuestionEdit.tsx b/packages/frontend/src/pages/QuestionEdit.tsx index 8523a6c..636a92c 100644 --- a/packages/frontend/src/pages/QuestionEdit.tsx +++ b/packages/frontend/src/pages/QuestionEdit.tsx @@ -604,7 +604,7 @@ export const QuestionEdit: React.FC = () => { > {mbQuiz.flatMap(q => maybe(q.quiz?.title)).orElse("---")} - {question.uid ? "Frage" : "Neue Frage"} + {question.uid ? i18n._("question") : i18n._("new-question")}
From 9479f6886e42b67c0d8862570de7008d4add4476 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Tue, 17 Dec 2024 16:51:47 +0100 Subject: [PATCH 30/51] Refactoring -> Dashboard.tsx into pages --- packages/frontend/src/App.tsx | 2 +- packages/frontend/src/actors/CurrentQuizActor.ts | 7 +++++++ packages/frontend/src/{ => pages}/Dashboard.tsx | 12 ++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) rename packages/frontend/src/{ => pages}/Dashboard.tsx (84%) diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index ba0393b..a82a47b 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -1,6 +1,6 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { Login } from "./Login"; -import { Dashboard } from "./Dashboard"; +import { Dashboard } from "./pages/Dashboard"; import { useEffect } from "react"; import { dynamicActivate, defaultLocale } from "./i18n"; import { getStoredSelectedLocal } from "./components/layout/LocaleSelect"; diff --git a/packages/frontend/src/actors/CurrentQuizActor.ts b/packages/frontend/src/actors/CurrentQuizActor.ts index e438e84..9a1d335 100644 --- a/packages/frontend/src/actors/CurrentQuizActor.ts +++ b/packages/frontend/src/actors/CurrentQuizActor.ts @@ -327,6 +327,13 @@ export class CurrentQuizActor extends StatefulActor Date: Tue, 17 Dec 2024 16:54:22 +0100 Subject: [PATCH 31/51] This belongs to a different branch...I am stupid --- packages/frontend/src/actors/CurrentQuizActor.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/frontend/src/actors/CurrentQuizActor.ts b/packages/frontend/src/actors/CurrentQuizActor.ts index 9a1d335..0f0a4fd 100644 --- a/packages/frontend/src/actors/CurrentQuizActor.ts +++ b/packages/frontend/src/actors/CurrentQuizActor.ts @@ -327,12 +327,6 @@ export class CurrentQuizActor extends StatefulActor Date: Wed, 18 Dec 2024 16:49:16 +0100 Subject: [PATCH 32/51] Translation problem with placeholder --- packages/frontend/src/components/modals/ShareQuizModal.tsx | 2 +- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/locales/en/messages.po | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/modals/ShareQuizModal.tsx b/packages/frontend/src/components/modals/ShareQuizModal.tsx index 210e3d3..6f3509b 100644 --- a/packages/frontend/src/components/modals/ShareQuizModal.tsx +++ b/packages/frontend/src/components/modals/ShareQuizModal.tsx @@ -149,7 +149,7 @@ export const ShareQuizModal: React.FC = ({ quiz, show, onClose }) => { value={name} autoFocus // placeholder="ID, Email oder Pseudonym" - placeholder="Email oder Pseudonym" + placeholder={i18n._("email-pseudonym-placeholder")} onChange={event => { const name = event.target.value; setName(name); diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 8e66278..b577bf0 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -1376,3 +1376,7 @@ msgstr "Neue Frage" #. js-lingui-explicit-id msgid "question" msgstr "Frage" + +#. js-lingui-explicit-id +msgid "email-pseudonym-placeholder" +msgstr "Email oder Pseudonym" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index d30ae83..966140b 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -1359,4 +1359,8 @@ msgstr "New question" #. js-lingui-explicit-id msgid "question" -msgstr "Question" \ No newline at end of file +msgstr "Question" + +#. js-lingui-explicit-id +msgid "email-pseudonym-placeholder" +msgstr "Email or pseudonym" \ No newline at end of file From 50bc409b8333ff46129699081dd9df807fb527d2 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 18 Dec 2024 18:31:59 +0100 Subject: [PATCH 33/51] Added gernders to Nutzer*in, Benutzer*in, ... and changed warning --- packages/frontend/src/locales/de/messages.js | 2 +- packages/frontend/src/locales/de/messages.po | 14 +++++++------- packages/frontend/src/locales/en/messages.js | 2 +- packages/frontend/src/locales/en/messages.po | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.js b/packages/frontend/src/locales/de/messages.js index 4244bc7..247898d 100644 --- a/packages/frontend/src/locales/de/messages.js +++ b/packages/frontend/src/locales/de/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer existiert nicht\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer deaktivieren\",\"user-activate-user-button\":\"Benutzer aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"activate-correct-answer\":\"Aktiviere die richtige Antwort\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator.\",\"error-message-user-deactivated-title\":\"Nutzer gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer*in ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer*in nicht bei RECAPP\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer*in deaktivieren\",\"user-activate-user-button\":\"Benutzer*in aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer*in\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"activate-correct-answer\":\"Aktiviere die richtige Antwort\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr*e Benutzer*in wurde deaktiviert. Bitte wenden Sie sich an Ihre*n Administrator*in.\",\"error-message-user-deactivated-title\":\"Nutzer*in gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index b577bf0..07f92da 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -223,12 +223,12 @@ msgstr "Fragetyp" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:221 msgid "share-quiz-modal.error-alert.already-exists" -msgstr "Benutzer ist bereits ausgewählt" +msgstr "Benutzer*in ist bereits ausgewählt" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:229 msgid "share-quiz-modal.error-alert.do-not-exist" -msgstr "Benutzer existiert nicht" +msgstr "Benutzer*in nicht bei RECAPP" #. js-lingui-explicit-id #: src/components/cards/CommentsContainer.tsx:44 @@ -333,12 +333,12 @@ msgstr "Letze Anmeldung: {date}" #. js-lingui-explicit-id #: src/components/modals/ChangeActiveModal.tsx:16 msgid "user-deactivate-user-button" -msgstr "Benutzer deaktivieren" +msgstr "Benutzer*in deaktivieren" #. js-lingui-explicit-id #: src/components/modals/ChangeActiveModal.tsx:16 msgid "user-activate-user-button" -msgstr "Benutzer aktivieren" +msgstr "Benutzer*in aktivieren" #. js-lingui-explicit-id #: src/components/modals/ChangeActiveModal.tsx:19 @@ -802,7 +802,7 @@ msgstr "Quizze" #. js-lingui-explicit-id #: src/Dashboard.tsx:44 msgid "dashboard-tab-label-users" -msgstr "Benutzer" +msgstr "Benutzer*in" #. js-lingui-explicit-id #: src/layout/HeaderSection.tsx:88 @@ -1015,11 +1015,11 @@ msgstr "Suchtext" #. js-lingui-explicit-id #~ msgid "error-message-user-deactivated" -#~ msgstr "Ihr Benutzer wurde deaktiviert. Bitte wenden Sie sich an Ihren Administrator." +#~ msgstr "Ihr*e Benutzer*in wurde deaktiviert. Bitte wenden Sie sich an Ihre*n Administrator*in." #. js-lingui-explicit-id #~ msgid "error-message-user-deactivated-title" -#~ msgstr "Nutzer gesperrt" +#~ msgstr "Nutzer*in gesperrt" #. js-lingui-explicit-id #~ msgid "archive-quiz-title" diff --git a/packages/frontend/src/locales/en/messages.js b/packages/frontend/src/locales/en/messages.js index ec76555..1af9027 100644 --- a/packages/frontend/src/locales/en/messages.js +++ b/packages/frontend/src/locales/en/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User doesn't exist\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"activate-correct-answer\":\"Activate the correct answer\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User not on RECAPP\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"activate-correct-answer\":\"Activate the correct answer\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 966140b..5b3592f 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -228,7 +228,7 @@ msgstr "User already selected" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:229 msgid "share-quiz-modal.error-alert.do-not-exist" -msgstr "User doesn't exist" +msgstr "User not on RECAPP" #. js-lingui-explicit-id #: src/components/cards/CommentsContainer.tsx:44 From ad5ffc429389a92fdd8538edd62cca697040cc06 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 08:49:16 +0100 Subject: [PATCH 34/51] Nutzer zu Nutzer*innen --- packages/frontend/src/locales/de/messages.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 07f92da..6e439de 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -499,7 +499,7 @@ msgstr "Hinzufügen" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:93 msgid "share-with-confirmed-users" -msgstr "Mit bestätigten Nutzern teilen" +msgstr "Mit bestätigten Nutzer*innen teilen" #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:191 From 58f87d820d3d636169055845727503047fe3a081 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 08:56:42 +0100 Subject: [PATCH 35/51] Changed name of button to share quiz with teachers --- packages/frontend/src/locales/de/messages.js | 2 +- packages/frontend/src/locales/de/messages.po | 2 +- packages/frontend/src/locales/en/messages.js | 2 +- packages/frontend/src/locales/en/messages.po | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/locales/de/messages.js b/packages/frontend/src/locales/de/messages.js index 247898d..f51a854 100644 --- a/packages/frontend/src/locales/de/messages.js +++ b/packages/frontend/src/locales/de/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer*in ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer*in nicht bei RECAPP\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer*in deaktivieren\",\"user-activate-user-button\":\"Benutzer*in aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Mit bestätigten Nutzern teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer*in\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"activate-correct-answer\":\"Aktiviere die richtige Antwort\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr*e Benutzer*in wurde deaktiviert. Bitte wenden Sie sich an Ihre*n Administrator*in.\",\"error-message-user-deactivated-title\":\"Nutzer*in gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Anmelden\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Mit Frage verlinkt\",\"running-quiz-tab.question-header\":\"Frage\",\"running-quiz-tab.button-label.submit\":\"Einreichen\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz abgeschlossen\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" Fragen beantwortet. Davon \",[\"questionsCountCorrect\"],\" richtige Antworten.\"],\"question-edit-page.title.edit-question\":\"Frage bearbeiten\",\"question-edit-page.title.new-question\":\"Neue Frage erstellen\",\"question-edit-page.input-label.group-name\":\"Fragengruppe\",\"question-edit-page.input-label.advisory-text\":\"Hinweistext\",\"question-edit-page.input-label.question\":\"Frage\",\"question-edit-page.button-label.edit\":\"Bearbeiten\",\"question-edit-page.button-label.add\":\"Hinzufügen\",\"question-edit-page.input-label.question-type\":\"Fragetyp\",\"share-quiz-modal.error-alert.already-exists\":\"Benutzer*in ist bereits ausgewählt\",\"share-quiz-modal.error-alert.do-not-exist\":\"Benutzer*in nicht bei RECAPP\",\"comments-container.toggle-button.label\":\"Kommentare anzeigen/ausblenden\",\"new-quiz-title\":\"Titel\",\"quiz-page.quiz-state.label\":\"Quiz-Status\",\"new-quiz-description\":\"Beschreibung\",\"new-quiz-group\":\"Gruppe\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Schließen\",\"comment-card.button-tooltip.accept\":\"Annehmen\",\"comment-card.button-tooltip.delete\":\"Löschen\",\"see-more-container.button-label\":\"Mehr anzeigen\",\"authored-by\":[\"von \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Bearbeiten\",\"question-card.button-tooltip.change-group\":\"Gruppe ändern\",\"question-card.button-tooltip.approve\":\"Freigeben\",\"question-card.button-tooltip.delete\":\"Löschen\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Lehrperson\",\"role-name-student\":\"Teilnehmende*r\",\"user-card.button-tooltip.edit\":\"Bearbeiten\",\"user-last-login: {date}\":[\"Letze Anmeldung: \",[\"date\"]],\"user-deactivate-user-button\":\"Benutzer*in deaktivieren\",\"user-activate-user-button\":\"Benutzer*in aktivieren\",\"user-change-active-flag-modal-title\":\"Benutzerstatus ändern\",\"yes\":\"Ja\",\"no\":\"Nein\",\"change-group-of-question-title\":\"Fragengruppe ändern\",\"change-group\":\"Gruppe ändern\",\"cancel\":\"Abbruch\",\"user-change-username-modal-title\":\"Benutzernamen ändern\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym ist nicht lang genug\",\"error-nickname-already-used\":\"Pseudonym ist bereits vergeben\",\"user-change-nickname-modal-title\":\"Pseudonym ändern\",\"delete-nickname-button\":\"Pseudonym löschen\",\"user-set-user-role-modal-title\":\"Benutzerrolle ändern\",\"user-set-role\":\"Rolle aktualisieren\",\"quiz-create-new-group-modal-title\":\"Name der Fragengruppe\",\"quiz-create-new-group-error-group-name-empty\":\"Gruppenname darf nicht leer sein\",\"quiz-create-new-group-error-group-name-not-unique\":\"Gruppenname muss innerhalb des Quiz eindeutig sein\",\"undefined-title\":\"undefined-title\",\"button-login-again\":\"Erneut anmelden\",\"quiz-export-modal-title\":\"Daten exportieren\",\"quiz-export-modal-text-pending\":\"Export wird vorbereitet.\",\"quiz-export-modal-text-ready\":\"Export abgeschlossen. Sie können die Datei jetzt herunterladen.\",\"download\":\"Herunterladen\",\"share-qr-code-header\":\"Teilnehmende können sich jetzt über Code oder Link in das Quiz einschreiben\",\"share-with-teachers-modal-title\":\"Lehrpersonen zum Teilen auswählen\",\"share-quiz-modal.button-tooltip.clear\":\"Löschen\",\"share-with-teachers-persons-to-add\":\"Hinzuzufügende Personen\",\"share-quiz-modal.button-label.add\":\"Hinzufügen\",\"share-with-confirmed-users\":\"Quiz teilen\",\"quiz-card-number-of-questions\":[[\"count\"],\" Fragen\"],\"quiz-card-number-of-participants\":[[\"count\"],\" Teilnehmende \"],\"quiz-show-qr-code-button\":\"QR-Code anzeigen\",\"quiz-questions-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-questions-tab-new-question-button\":\"Neue Frage\",\"button-label-edit\":\"bearbeiten\",\"quiz-questions-tab-empty-group-message\":\"Noch keine Fragen hinzugefügt worden\",\"start-quiz-mode-button\":\"Quizmodus starten\",\"freeze-quiz-button\":\"Quiz stoppen\",\"edit-quiz-button\":\"Editiermodus aktivieren\",\"quiz-description\":\"Beschreibung\",\"number-of-participants\":\"Anzahl Teilnehmende\",\"teachers\":\"Lehrpersonen\",\"quiz-allows-student-comments\":\"Kommentare von Teilnehmenden im Quizmodus erlauben\",\"quiz-allows-student-questions\":\"Fragen durch Teilnehmende erstellen lassen\",\"quiz-student-participation\":\"Teilnahmemöglichkeiten\",\"quiz-allows-anonymous-participation\":\"Anonyme Teilnahme\",\"quiz-allows-participation-via-nickname\":\"Teilnahme mit Pseudonym\",\"quiz-allows-participation-via-realname\":\"Teilnahme mit echtem Namen\",\"quiz-allowed-question-types\":\"Erlaubte Fragentypen\",\"quiz-allows-text-questions\":\"Freitextfragen erlauben\",\"quiz-allows-single-choice-questions\":\"Single-Choice Fragen erlauben\",\"quiz-allows-multiple-choice-realname\":\"Multiple-Choice Fragen erlauben\",\"quiz-enable-question-shufflling\":\"Fragen im Quizmodus mischen\",\"archive-quiz-button\":\"Quiz archivieren\",\"export-quiz-button\":\"Daten exportieren\",\"quiz-data-tab.button-tooltip.edit\":\"Bearbeiten\",\"quiz-data-tab.button-tooltip.share\":\"Teilen\",\"button-label-share\":\"Teilen\",\"export-quiz-statistics-button\":\"Quizstatistik exportieren\",\"export-question-statistics-button\":\"Fragenstatistik exportieren\",\"no-data-yet\":\"Es liegen noch keine auswertbaren Daten vor\",\"details\":\"Details\",\"question-stats-prefix\":\"Frage: \",\"question-stats-info\":[[\"participants\"],\" Teilnehmende von \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) haben die Frage bearbeitet\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" Antworten wurden gegeben\"],\"question-stats-given-answers\":\"Es wurden folgenden Antworten gegeben\",\"question-stats-correct-answers\":[[\"passed\"],\" von \",[\"participants\"],\" Antworten waren richtig.\"],\"question-stats-answer-prefix\":\"Antwort: \",\"question-stats-back-to-quiz-button\":\"Zurück zum Quiz\",\"question-stats-previous-question-button\":\"Vorherige Frage\",\"question-stats-next-question-button\":\"Nächste Frage\",\"running-quiz-tab.button-tooltip.comment\":\"Kommentar\",\"quiz-card-last-change\":\"Letzte Änderung\",\"quiz-card.button-tooltip.edit\":\"Bearbeiten\",\"quiz-card.button-tooltip.share\":\"Teilen\",\"quiz-card.button-tooltip.delete\":\"Löschen\",\"button-new-quiz\":\"Neues Quiz\",\"dashboard-tab-label-quizzes\":\"Quizze\",\"dashboard-tab-label-users\":\"Benutzer*in\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Pseudonym bearbeiten oder hinzufügen\",\"header-section.button-tooltip.logout\":\"Abmelden\",\"header.logout\":\"Abmelden\",\"new-quiz\":\"Neues Quiz\",\"quiz-title\":\"Titel\",\"error-quiz-title-too-short\":\"Titel ist zu kurz\",\"create-quiz-button\":\"Quiz anlegen\",\"single-choice-selection\":\"Einzelauswahl\",\"multiple-choice-selection\":\"Mehrfachauswahl\",\"text-type-selection\":\"Freitext\",\"question-edit.button-tooltip.check\":\"Freigeben\",\"question-edit.button-tooltip.edit-title-text\":\"Bearbeiten\",\"question-edit.button-tooltip.edit-comment-text\":\"Kommentar bearbeiten\",\"question-edit.button-tooltip.edit-hint-title\":\"Bearbeiten\",\"activate-all-correct-answers\":\"Aktiviere alle richtigen Antworten\",\"activate-correct-answer\":\"Aktiviere die richtige Antwort\",\"question-edit.button-tooltip.edit-answer\":\"Antwort bearbeiten\",\"question-edit.button-tooltip.delete-answer\":\"Antwort löschen\",\"add-answer-button\":\"Antwort hinzufügen\",\"save-question-button\":\"Frage speichern\",\"quiz-not-found-error-message\":\"Das Quiz konnte nicht geöffnet werden. Das tut uns leid.\",\"back-to-dashboard-link\":\"Zurück zum Dashboard\",\"comment-row-new-comment-button\":\"Neuer Kommentar\",\"user-admin-panel-title\":\"Benutzerverwaltung\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Suchtext\",\"quiz-card-button-tooltip-edit\":\"Bearbeiten\",\"quiz-card-button-tooltip-share\":\"Teilen\",\"quiz-card-button-tooltip-delete\":\"Löschen\",\"quiz-questioins-tab-add-group-button\":\"Gruppe hinzufügen\",\"quiz-tab-label-data\":\"Quizdaten\",\"quiz-tab-label-questions\":\"Quizfragen\",\"quiz-tab-label-statistics\":\"Statistische Auswertung\",\"edit-question-title\":\"Frage bearbeiten\",\"edit-hint-title\":\"Hinweistext bearbeiten\",\"edit-answer-text\":\"Antwort bearbeiten\",\"app.could_not_refresh_token\":\"Anmeldung konnte nicht aktualisiert werden\",\"number-of-quiz-participants\":\"Zahl der Teilnehmenden\",\"teachers-in-quiz\":\"Lehrpersonen mit Zugriff\",\"number-of-quiz-questions\":\"Zahl der Fragen\",\"error-message-no-server-connection\":\"Es konnte keine Verbindung mit dem Server hergestellt werden. Bitte melden Sie sich neu an.\",\"error-message-no-server-connection-title\":\"Keine Serververbindung\",\"error-message-user-deactivated\":\"Ihr*e Benutzer*in wurde deaktiviert. Bitte wenden Sie sich an Ihre*n Administrator*in.\",\"error-message-user-deactivated-title\":\"Nutzer*in gesperrt\",\"archive-quiz-title\":\"Quiz archivieren\",\"archive-quiz-text\":\"Möchten Sie dieses Quiz archivieren? Es wird nicht mehr in der Übersicht angezeigt, ist über existierende Links und QR-Codes aber noch erreichbar. Alternativ können Sie das Quiz auch unwiderrufllich löschen. Achtung, es erfolgt keine weitere Rückfrage!\",\"title-set-quiz-mode-edit\":\"Editiermodus starten\",\"info-set-quiz-mode-edit\":\"Mit dem Starten des Editiermodus werden die Statistiken invalidiert. Editieren starten?\",\"title-set-quiz-mode-stopped\":\"Quiz einfrieren\",\"info-set-quiz-mode-stopped\":\"Möchten Sie das Quiz temporär stoppen?\",\"warning-set-quiz-mode-started\":\"Mit dem Start des Quiz werden alle Statistiken gelöscht! Fortfahren?\",\"info-set-quiz-mode-started\":\"Soll der Quizmodus gestartet werden?\",\"title-set-quiz-mode-started\":\"Quizmodus starten\",\"add\":\"Hinzufügen\",\"edit-title-text\":\"Text bearbeiten\",\"remove-edit-mode-of-question-title\":\"Editiermodus wieder aktivieren?\",\"remove-edit-mode-of-question-text\":\"Die Frage befindet ist durch einen anderen Editiervorgang gesperrt worden. Möchten Sie den Editiervorgang wieder aktivieren?\",\"quiz-import-modal-title\":\"Ein Quiz importieren\",\"quiz-import-modal-message\":\"Wählen Sie eine Quiz-Datei aus, um diese zu importieren\",\"import\":\"Importieren\",\"button-import-quiz\":\"Quiz importieren\",\"dashboard-show-archived-quizzes-switch\":\"Archivierte Quizze anzeigen\",\"delete-quiz-button\":\"Quiz unwiderruflich löschen\",\"anonymous\":\"ANONYM\",\"author\":\"Autor\",\"new-comment-title\":\"Neuer Kommentar\",\"back-to-quiz-button\":\"Zurück zum Quiz\",\"question-card.button-tooltip.view\":\"Frage anzeigen\",\"quiz-hide-comments-switch\":\"Kommentarleiste verbergen\",\"leave-quiz-modal-title\":\"Quiz verlassen\",\"leave-quiz-modal-text\":\"Sie sind im Begriff, das Quiz zu verlassen. Es wird Ihnen nicht mehr im Dashboard angezeigt und Sie können nicht länger am Quiz teilnehmen oder es modifizieren. Wirklich verlassen?\",\"quiz-card-teachers-label\":\"Lehrpersonen\",\"answer-correct-title\":\"Antwort richtig\",\"answer-correct\":\"Die Frage wurde richtig beantwortet.\",\"answer-wrong-title\":\"Antwort falsch\",\"answer-wrong\":\"Diese Antwort ist leider falsch\",\"reset-stats-button\":\"Statistik zurücksetzen\",\"title-reset-quiz\":\"Statistik zurücksetzen\",\"info-reset-quiz\":\"Möchten Sie alle erfassten Antworten löschen?\",\"delete-question-title\":\"Frage löschen\",\"delete-question-text\":\"Möchten Sie die Frage unwiderruflich löschen?\",\"question-card.button-tooltip.unapprove\":\"Freigabe zurücknehmen\",\"nickname-not-set\":\"Nicht gesetzt\",\"998VJr\":\"Du\",\"dzcobz\":\"Deine Antwort\"}")}; diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 6e439de..f173d45 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -499,7 +499,7 @@ msgstr "Hinzufügen" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:93 msgid "share-with-confirmed-users" -msgstr "Mit bestätigten Nutzer*innen teilen" +msgstr "Quiz teilen" #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:191 diff --git a/packages/frontend/src/locales/en/messages.js b/packages/frontend/src/locales/en/messages.js index 1af9027..2993ca5 100644 --- a/packages/frontend/src/locales/en/messages.js +++ b/packages/frontend/src/locales/en/messages.js @@ -1,2 +1,2 @@ -/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User not on RECAPP\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share with confirmed users\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"activate-correct-answer\":\"Activate the correct answer\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; +/*eslint-disable*/module.exports={messages:JSON.parse("{\"login-page.login\":\"Login\",\"comment-editor-modal.link-to-question.checkbox-label\":\"Link to question\",\"running-quiz-tab.question-header\":\"Question\",\"running-quiz-tab.button-label.submit\":\"Submit\",\"running-quiz-tab.completed-quiz-card.header\":\"Quiz completed\",\"running-quiz-tab.completed-quiz-card.quiz-result\":[[\"questionsCountTotal\"],\" questions answered. Of which, \",[\"questionsCountCorrect\"],\" correct answers.\"],\"question-edit-page.title.edit-question\":\"Edit question\",\"question-edit-page.title.new-question\":\"New question\",\"question-edit-page.input-label.group-name\":\"Question group\",\"question-edit-page.input-label.advisory-text\":\"Hint text\",\"question-edit-page.input-label.question\":\"Question\",\"question-edit-page.button-label.edit\":\"Edit\",\"question-edit-page.button-label.add\":\"Add\",\"question-edit-page.input-label.question-type\":\"Question type\",\"share-quiz-modal.error-alert.already-exists\":\"User already selected\",\"share-quiz-modal.error-alert.do-not-exist\":\"User not on RECAPP\",\"comments-container.toggle-button.label\":\"Show/hide comments\",\"new-quiz-title\":\"Title\",\"quiz-page.quiz-state.label\":\"Quiz state\",\"new-quiz-description\":\"Description\",\"new-quiz-group\":\"Group\",\"comment-card.button-tooltip.upvote\":\"Upvote\",\"close\":\"Close\",\"comment-card.button-tooltip.accept\":\"Accept\",\"comment-card.button-tooltip.delete\":\"Delete\",\"see-more-container.button-label\":\"See more\",\"authored-by\":[\"by \",[\"author\"]],\"question-card.button-tooltip.edit\":\"Edit\",\"question-card.button-tooltip.change-group\":\"Change group\",\"question-card.button-tooltip.approve\":\"Approve\",\"question-card.button-tooltip.delete\":\"Delete\",\"role-name-admin\":\"Admin\",\"role-name-teacher\":\"Teacher\",\"role-name-student\":\"Participant\",\"user-card.button-tooltip.edit\":\"Edit\",\"user-last-login: {date}\":[\"Last login: \",[\"date\"]],\"user-deactivate-user-button\":\"Deactivate user\",\"user-activate-user-button\":\"Activate user\",\"user-change-active-flag-modal-title\":\"Change user status\",\"yes\":\"Yes\",\"no\":\"No\",\"change-group-of-question-title\":\"Change question group\",\"change-group\":\"Change group\",\"cancel\":\"Cancel\",\"user-change-username-modal-title\":\"Change username\",\"okay\":\"OK\",\"error-nickname-to-short\":\"Pseudonym is not long enough\",\"error-nickname-already-used\":\"Pseudonym is already taken\",\"user-change-nickname-modal-title\":\"Change pseudonym\",\"delete-nickname-button\":\"Delete pseudonym\",\"user-set-user-role-modal-title\":\"Change user role\",\"user-set-role\":\"Update role\",\"quiz-create-new-group-modal-title\":\"Name of question group\",\"quiz-create-new-group-error-group-name-empty\":\"Group name must not be empty\",\"quiz-create-new-group-error-group-name-not-unique\":\"Group name must not be empty\",\"undefined-title\":\"undefined title\",\"button-login-again\":\"Log in again\",\"quiz-export-modal-title\":\"Export data\",\"quiz-export-modal-text-pending\":\"Export is being prepared.\",\"quiz-export-modal-text-ready\":\"Export completed. You can now download the file.\",\"download\":\"Download\",\"share-qr-code-header\":\"Participants can now register for the quiz via code or link\",\"share-with-teachers-modal-title\":\"Select teachers for sharing\",\"share-quiz-modal.button-tooltip.clear\":\"Clear\",\"share-with-teachers-persons-to-add\":\"People to be added\",\"share-quiz-modal.button-label.add\":\"Add\",\"share-with-confirmed-users\":\"Share quiz\",\"quiz-card-number-of-questions\":[[\"count\"],\" questions\"],\"quiz-card-number-of-participants\":[[\"count\"],\" participants \"],\"quiz-show-qr-code-button\":\"Show QR code\",\"quiz-questions-tab-add-group-button\":\"Add group\",\"quiz-questions-tab-new-question-button\":\"New question\",\"button-label-edit\":\"edit\",\"quiz-questions-tab-empty-group-message\":\"No questions have been added to the group\",\"start-quiz-mode-button\":\"Start quiz\",\"freeze-quiz-button\":\"Stop quiz\",\"edit-quiz-button\":\"Edit quiz\",\"quiz-description\":\"Description\",\"number-of-participants\":\"Number of participants\",\"teachers\":\"Teachers\",\"quiz-allows-student-comments\":\"Allow participant comments in quiz mode\",\"quiz-allows-student-questions\":\"Allow participants to set questions\",\"quiz-student-participation\":\"Participation options\",\"quiz-allows-anonymous-participation\":\"Anonymous participation\",\"quiz-allows-participation-via-nickname\":\"Participation with pseudonym\",\"quiz-allows-participation-via-realname\":\"Participation with real name\",\"quiz-allowed-question-types\":\"Allowed question types\",\"quiz-allows-text-questions\":\"Allow free-text questions\",\"quiz-allows-single-choice-questions\":\"Allow single-choice questions\",\"quiz-allows-multiple-choice-realname\":\"Allow multiple-choice questions\",\"quiz-enable-question-shufflling\":\"Shuffle questions in quiz mode\",\"archive-quiz-button\":\"Archive quiz\",\"export-quiz-button\":\"Export data\",\"quiz-data-tab.button-tooltip.edit\":\"Edit\",\"quiz-data-tab.button-tooltip.share\":\"Share\",\"button-label-share\":\"Share\",\"export-quiz-statistics-button\":\"Export quiz statistics\",\"export-question-statistics-button\":\"Export question statistics\",\"no-data-yet\":\"No analyzable data is available yet\",\"details\":\"Details\",\"question-stats-prefix\":\"Question: \",\"question-stats-info\":[[\"participants\"],\" participants from \",[\"maxParticipants\"],\" (\",[\"ratio\"],\" %) have answered the question\"],\"question-stats-answers-given\":[[\"numberOfAnswers\"],\" answers were given\"],\"question-stats-given-answers\":\"The following answers were given\",\"question-stats-correct-answers\":[[\"passed\"],\" of \",[\"participants\"],\" answers were correct.\"],\"question-stats-answer-prefix\":\"Answer: \",\"question-stats-back-to-quiz-button\":\"Back to Quiz\",\"question-stats-previous-question-button\":\"Previous question\",\"question-stats-next-question-button\":\"Next question\",\"running-quiz-tab.button-tooltip.comment\":\"Comment\",\"quiz-card-last-change\":\"Last change\",\"quiz-card.button-tooltip.edit\":\"Edit\",\"quiz-card.button-tooltip.share\":\"Share\",\"quiz-card.button-tooltip.delete\":\"Delete\",\"button-new-quiz\":\"New quiz\",\"dashboard-tab-label-quizzes\":\"Quizzes\",\"dashboard-tab-label-users\":\"Users\",\"header-section.button-tooltip.edit-or-add-pseudonym\":\"Edit or add pseudonym\",\"header-section.button-tooltip.logout\":\"Logout\",\"header.logout\":\"Logout\",\"new-quiz\":\"New quiz\",\"quiz-title\":\"Title\",\"error-quiz-title-too-short\":\"Title is too short\",\"create-quiz-button\":\"Create quiz\",\"single-choice-selection\":\"Single choice\",\"multiple-choice-selection\":\"Multiple choice\",\"text-type-selection\":\"Free text\",\"question-edit.button-tooltip.check\":\"Select\",\"question-edit.button-tooltip.edit-title-text\":\"Edit\",\"question-edit.button-tooltip.edit-comment-text\":\"Edit comment\",\"question-edit.button-tooltip.edit-hint-title\":\"Edit title\",\"activate-all-correct-answers\":\"Activate all correct answers\",\"activate-correct-answer\":\"Activate the correct answer\",\"question-edit.button-tooltip.edit-answer\":\"Edit answer\",\"question-edit.button-tooltip.delete-answer\":\"Delete answer\",\"add-answer-button\":\"Add answer\",\"save-question-button\":\"Save question\",\"quiz-not-found-error-message\":\"Sorry, the quiz could not be opened\",\"back-to-dashboard-link\":\"Back to dashboard\",\"comment-row-new-comment-button\":\"New comment\",\"user-admin-panel-title\":\"User administration\",\"user-admin-panel.button-tooltip.filter\":\"Filter\",\"user-admin-panel-search-text\":\"Search text\",\"quiz-card-button-tooltip-edit\":\"Edit\",\"quiz-card-button-tooltip-share\":\"Share\",\"quiz-card-button-tooltip-delete\":\"Delete\",\"quiz-questioins-tab-add-group-button\":\"Add group\",\"quiz-tab-label-data\":\"Quiz data\",\"quiz-tab-label-questions\":\"Quiz questions\",\"quiz-tab-label-statistics\":\"Statistical evaluation\",\"edit-question-title\":\"Edit question\",\"edit-hint-title\":\"Edit hint text\",\"edit-answer-text\":\"Edit answer\",\"app.could_not_refresh_token\":\"Login could not be updated\",\"number-of-quiz-participants\":\"Number of participants\",\"teachers-in-quiz\":\"Teaching staff with access\",\"number-of-quiz-questions\":\"Number of questions\",\"error-message-no-server-connection\":\"No connection to the server could be established. Please log in again.\",\"error-message-no-server-connection-title\":\"No server connection\",\"error-message-user-deactivated\":\"Your user has been deactivated. Please contact your administrator.\",\"error-message-user-deactivated-title\":\"User deactivated\",\"archive-quiz-title\":\"Archive quiz\",\"archive-quiz-text\":\"Would you like to archive this quiz? It will no longer be displayed in the overview but can still be accessed via existing links and QR codes. Alternatively, you can delete the quiz permanently. Caution, there will be no further confirmation!\",\"title-set-quiz-mode-edit\":\"Start edit mode\",\"info-set-quiz-mode-edit\":\"Statistics are invalidated when editing mode is started. Start editing?\",\"title-set-quiz-mode-stopped\":\"Freeze quiz\",\"info-set-quiz-mode-stopped\":\"Do you wish to temporarily stop the quiz?\",\"warning-set-quiz-mode-started\":\"All statistics will be deleted when you start the quiz! Continue?\",\"info-set-quiz-mode-started\":\"Should the quiz mode be started?\",\"title-set-quiz-mode-started\":\"Start quiz mode\",\"add\":\"Add\",\"edit-title-text\":\"Edit text\",\"remove-edit-mode-of-question-title\":\"Reactivate edit mode?\",\"remove-edit-mode-of-question-text\":\"The question has been locked by another editing process. Would you like to reactivate the editing process?\",\"quiz-import-modal-title\":\"Import a quiz\",\"quiz-import-modal-message\":\"Select a quiz file to import\",\"import\":\"Import\",\"button-import-quiz\":\"Import quiz\",\"dashboard-show-archived-quizzes-switch\":\"Show archived quizzes\",\"delete-quiz-button\":\"Permanently delete quiz\",\"anonymous\":\"ANONYMOUS\",\"author\":\"Author\",\"new-comment-title\":\"New comment\",\"back-to-quiz-button\":\"Back to quiz\",\"question-card.button-tooltip.view\":\"Show question\",\"quiz-hide-comments-switch\":\"Hide comment list\",\"leave-quiz-modal-title\":\"Leave quiz\",\"leave-quiz-modal-text\":\"You are about to leave the quiz. It will no longer be displayed in your dashboard and you won't be able to modify it or participate. Really leave?\",\"quiz-card-teachers-label\":\"Teaching staff\",\"answer-correct-title\":\"Correct\",\"answer-correct\":\"Your answer is correct.\",\"answer-wrong-title\":\"Incorrect\",\"answer-wrong\":\"Sorry, your answer is incorrect.\",\"reset-stats-button\":\"Reset statistics\",\"title-reset-quiz\":\"Reset statistics\",\"info-reset-quiz\":\"Reset the statistics of all given answers?\",\"delete-question-title\":\"Delete question\",\"delete-question-text\":\"Delete question from quiz? This operation is irrevocable.\",\"question-card.button-tooltip.unapprove\":\"Revoke approval\",\"nickname-not-set\":\"Not set\",\"998VJr\":\"You\",\"dzcobz\":\"Your answer\"}")}; diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 5b3592f..25d0cc8 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -504,7 +504,7 @@ msgstr "Add" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:93 msgid "share-with-confirmed-users" -msgstr "Share with confirmed users" +msgstr "Share quiz" #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:191 From 0f7cfd504d65f14ddcd1d5867d1e91cabefc0b26 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 09:12:07 +0100 Subject: [PATCH 36/51] Added tooltip for share-with-confirmed-users button. --- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/locales/en/messages.po | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index f173d45..1cee144 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -501,6 +501,10 @@ msgstr "Hinzufügen" msgid "share-with-confirmed-users" msgstr "Quiz teilen" +#. js-lingui-explicit-id +msgid "share-with-confirmed-users-tooltip" +msgstr "Quiz erscheint im Dashboard der hinzugefügten Lehrpersonen." + #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:191 #: src/components/quiz-tabs/QuestionsTab.tsx:230 diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 25d0cc8..5aeb98e 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -506,6 +506,10 @@ msgstr "Add" msgid "share-with-confirmed-users" msgstr "Share quiz" +#. js-lingui-explicit-id +msgid "share-with-confirmed-users-tooltip" +msgstr "Quiz appears in the dashboard of the added teachers." + #. js-lingui-explicit-id #: src/components/quiz-tabs/QuestionsTab.tsx:191 #: src/components/quiz-tabs/QuestionsTab.tsx:230 From fd3d4972ca9a0679ffd1d79f9d0fc36dfe1fe77d Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 09:33:33 +0100 Subject: [PATCH 37/51] Changed share with confirmed users button to button with tooltip --- .../frontend/src/components/modals/ShareQuizModal.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/modals/ShareQuizModal.tsx b/packages/frontend/src/components/modals/ShareQuizModal.tsx index 6f3509b..763846e 100644 --- a/packages/frontend/src/components/modals/ShareQuizModal.tsx +++ b/packages/frontend/src/components/modals/ShareQuizModal.tsx @@ -172,9 +172,14 @@ export const ShareQuizModal: React.FC = ({ quiz, show, onClose }) => { - + From d781161b6fe42490fb67018ce0a91ba3409117ba Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 10:07:35 +0100 Subject: [PATCH 38/51] Changed share-quiz-model.button-label.add to a button with tooltip --- packages/frontend/src/components/modals/ShareQuizModal.tsx | 5 +++-- packages/frontend/src/locales/de/messages.po | 6 +++++- packages/frontend/src/locales/en/messages.po | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/modals/ShareQuizModal.tsx b/packages/frontend/src/components/modals/ShareQuizModal.tsx index 763846e..3c05301 100644 --- a/packages/frontend/src/components/modals/ShareQuizModal.tsx +++ b/packages/frontend/src/components/modals/ShareQuizModal.tsx @@ -155,14 +155,15 @@ export const ShareQuizModal: React.FC = ({ quiz, show, onClose }) => { setName(name); }} /> - + diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 1cee144..87f738a 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -493,9 +493,13 @@ msgstr "Hinzuzufügende Personen" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:92 -msgid "share-quiz-modal.button-label.add" +msgid "" msgstr "Hinzufügen" +#. js-lingui-explicit-id +msgid "share-quiz-modal.button-label.add-tooltip" +msgstr "Nur Lehrpersonen, die zuvor auf RecApp zugegriffen haben, können hinzugefügt werden." + #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:93 msgid "share-with-confirmed-users" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 5aeb98e..13ea0c4 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -501,6 +501,10 @@ msgstr "People to be added" msgid "share-quiz-modal.button-label.add" msgstr "Add" +#. js-lingui-explicit-id +msgid "share-quiz-modal.button-label.add-tooltip" +msgstr "Only teachers who have previously accessed RecApp are eligible to be added." + #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:93 msgid "share-with-confirmed-users" From 33ea684919add8e83e1ce318cef32c7effb98745 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 10:09:44 +0100 Subject: [PATCH 39/51] Fix --- packages/frontend/src/locales/de/messages.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index 87f738a..c011f78 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -493,7 +493,7 @@ msgstr "Hinzuzufügende Personen" #. js-lingui-explicit-id #: src/components/modals/ShareQuizModal.tsx:92 -msgid "" +msgid "share-quiz-modal.button-label.add" msgstr "Hinzufügen" #. js-lingui-explicit-id From 2cebb9d8555c14a9c04e85466d95b83e7b00a4c6 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 14:24:24 +0100 Subject: [PATCH 40/51] Upvoted comments should be indicated by green colour --- .../frontend/src/components/cards/CommentCard.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/cards/CommentCard.tsx b/packages/frontend/src/components/cards/CommentCard.tsx index 98ba85d..8680475 100644 --- a/packages/frontend/src/components/cards/CommentCard.tsx +++ b/packages/frontend/src/components/cards/CommentCard.tsx @@ -63,6 +63,14 @@ export const CommentCardContent: React.FC< isDisplayedInModal, isCommentSectionVisible, }) => { + + const [upvoted, setUpvoted] = useState(false); + + const onUpvoteHandler = () => { + setUpvoted(!upvoted); + onUpvote(); + }; + const { rendered } = useRendered({ value: comment.text }); // const isQuizTeacher = teachers.includes(userId); @@ -107,8 +115,8 @@ export const CommentCardContent: React.FC<
From fc19d17e235f1ad9b6ce68df700d7c072821396e Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 8 Jan 2025 15:10:22 +0100 Subject: [PATCH 41/51] remove upvote colouring --- .../src/components/cards/CommentCard.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/frontend/src/components/cards/CommentCard.tsx b/packages/frontend/src/components/cards/CommentCard.tsx index 8680475..533000b 100644 --- a/packages/frontend/src/components/cards/CommentCard.tsx +++ b/packages/frontend/src/components/cards/CommentCard.tsx @@ -64,13 +64,14 @@ export const CommentCardContent: React.FC< isCommentSectionVisible, }) => { - const [upvoted, setUpvoted] = useState(false); + //const [upvoted, setUpvoted] = useState(false); + // this needs to be saved for every participant not in general + + //const onUpvoteHandler = () => { + // setUpvoted(!upvoted); + // onUpvote(); + //}; - const onUpvoteHandler = () => { - setUpvoted(!upvoted); - onUpvote(); - }; - const { rendered } = useRendered({ value: comment.text }); // const isQuizTeacher = teachers.includes(userId); @@ -115,8 +116,8 @@ export const CommentCardContent: React.FC<
From 20ec8325e7363407ecc9996bcfde7427e54cea7a Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 15 Jan 2025 15:33:16 +0100 Subject: [PATCH 42/51] nickname to pseudonym --- packages/frontend/src/locales/en/messages.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 13ea0c4..499b761 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -37,7 +37,7 @@ msgstr "Anonymous" #. js-lingui-explicit-id #: src/layout/HeaderSection.tsx:88 msgid "participation-select-option.nickname" -msgstr "Nickname" +msgstr "Pseudonym" #. js-lingui-explicit-id #: src/layout/HeaderSection.tsx:88 From 6666969cd0cf0b820cb2a61e6f892473618b9fbe Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 15 Jan 2025 16:22:13 +0100 Subject: [PATCH 43/51] Testing to display question number in statistics view --- .../frontend/src/components/quiz-tabs/QuizStatsDetails.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx b/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx index ff440d4..3dfb866 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx @@ -95,8 +95,8 @@ export const QuizStatsDetails = ({
{/*

*/} {/* {question.text} */} -

- +

+ {(questionIndex) + 1} /{" "} {questionsList.length}

From 7495c23d9f4db98970036ea7c9c7bbf2fc51bf11 Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 15 Jan 2025 16:40:59 +0100 Subject: [PATCH 44/51] Removed margin around stats --- .../frontend/src/components/quiz-tabs/QuizStatsDetails.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx b/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx index 3dfb866..db1ae1d 100644 --- a/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx +++ b/packages/frontend/src/components/quiz-tabs/QuizStatsDetails.tsx @@ -149,7 +149,7 @@ export const QuizStatsDetails = ({ {question.type !== "TEXT" && (
-

-

-

Date: Wed, 22 Jan 2025 10:17:22 +0100 Subject: [PATCH 45/51] Change color of upvote button when upvoted --- .../frontend/src/components/cards/CommentCard.tsx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/components/cards/CommentCard.tsx b/packages/frontend/src/components/cards/CommentCard.tsx index 533000b..b50f31b 100644 --- a/packages/frontend/src/components/cards/CommentCard.tsx +++ b/packages/frontend/src/components/cards/CommentCard.tsx @@ -64,14 +64,6 @@ export const CommentCardContent: React.FC< isCommentSectionVisible, }) => { - //const [upvoted, setUpvoted] = useState(false); - // this needs to be saved for every participant not in general - - //const onUpvoteHandler = () => { - // setUpvoted(!upvoted); - // onUpvote(); - //}; - const { rendered } = useRendered({ value: comment.text }); // const isQuizTeacher = teachers.includes(userId); @@ -116,8 +108,8 @@ export const CommentCardContent: React.FC<

From e3716599d3395bba69ad3b6f2013dcc2a77ff40b Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 22 Jan 2025 10:42:37 +0100 Subject: [PATCH 46/51] includes not in...this is not python --- packages/frontend/src/components/cards/CommentCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/cards/CommentCard.tsx b/packages/frontend/src/components/cards/CommentCard.tsx index b50f31b..2e3c4f0 100644 --- a/packages/frontend/src/components/cards/CommentCard.tsx +++ b/packages/frontend/src/components/cards/CommentCard.tsx @@ -108,7 +108,7 @@ export const CommentCardContent: React.FC<
From 2de3c360afd5257b52d467ba9e76cb20b673352f Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Wed, 22 Jan 2025 11:39:22 +0100 Subject: [PATCH 47/51] Deleted edit button in dashboard --- packages/frontend/src/components/quizzes-panel/QuizCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx index 9565c82..86b0eaf 100644 --- a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx +++ b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx @@ -114,7 +114,7 @@ export const QuizCard: React.FC<{ ) : null} - {isQuizEditable ? ( + {/*
{isQuizEditable ? ( - ) : null} + ) : null} */} {isAuthorized ? ( Date: Sun, 26 Jan 2025 21:27:28 +0100 Subject: [PATCH 48/51] added label for stop button in dashboard --- packages/frontend/src/locales/de/messages.po | 4 ++++ packages/frontend/src/locales/en/messages.po | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/frontend/src/locales/de/messages.po b/packages/frontend/src/locales/de/messages.po index c011f78..32d383e 100644 --- a/packages/frontend/src/locales/de/messages.po +++ b/packages/frontend/src/locales/de/messages.po @@ -787,6 +787,10 @@ msgstr "Bearbeiten" msgid "quiz-card.button-tooltip.start" msgstr "Starten" +#. js-lingui-explicit-id +msgid "quiz-card.button-tooltip.stop" +msgstr "Stoppen" + #. js-lingui-explicit-id #: src/components/quizzes-panel/QuizCard.tsx:66 msgid "quiz-card.button-tooltip.share" diff --git a/packages/frontend/src/locales/en/messages.po b/packages/frontend/src/locales/en/messages.po index 499b761..749ee16 100644 --- a/packages/frontend/src/locales/en/messages.po +++ b/packages/frontend/src/locales/en/messages.po @@ -786,6 +786,10 @@ msgstr "Edit" msgid "quiz-card.button-tooltip.start" msgstr "Start" +#. js-lingui-explicit-id +msgid "quiz-card.button-tooltip.stop" +msgstr "Stop" + #. js-lingui-explicit-id #: src/components/quizzes-panel/QuizCard.tsx:66 msgid "quiz-card.button-tooltip.share" From 76dac5e0cc73f032c46e40e2c9857c9f50300d0e Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Sun, 26 Jan 2025 22:05:26 +0100 Subject: [PATCH 49/51] Added a stop button in Dashboard when quiz is started --- .../src/components/quizzes-panel/QuizCard.tsx | 15 +++++++++++++-- .../src/components/quizzes-panel/QuizzesPanel.tsx | 3 +++ packages/frontend/src/pages/QuizPage.tsx | 4 ++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx index 86b0eaf..6009e5d 100644 --- a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx +++ b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx @@ -5,7 +5,7 @@ import { i18n } from "@lingui/core"; import { fromTimestamp } from "itu-utils"; import { Quiz, QuestionGroup, toId } from "@recapp/models"; import Card from "react-bootstrap/Card"; -import { Pencil, Play, Share, Trash } from "react-bootstrap-icons"; +import { Pencil, Play, Share, Trash, StopFill } from "react-bootstrap-icons"; import { ButtonWithTooltip } from "../ButtonWithTooltip"; import { QuizStateBadge } from "../QuizStateBadge"; import { useLocalUser } from "../../hooks/state-actor/useLocalUser"; @@ -17,9 +17,10 @@ export const QuizCard: React.FC<{ quiz: Partial; teachers: string[]; onStart: () => void; + onStop: () => void; onShare: () => void; onDelete?: () => void; -}> = ({ quiz, teachers, onShare, onDelete, onStart }) => { +}> = ({ quiz, teachers, onShare, onDelete, onStart, onStop }) => { const nav = useNavigate(); const { localUser } = useLocalUser(); @@ -114,6 +115,16 @@ export const QuizCard: React.FC<{ ) : null} + {isQuizStateStarted && isAuthorized ? ( + + + + ) : null} {/*
{isQuizEditable ? ( { onStart={() => { nav({ pathname: "/Dashboard/quiz" }, { state: { quizId: q.uid, start: true } }); }} + onStop={() => { + nav({ pathname: "/Dashboard/quiz" }, { state: { quizId: q.uid, stop: true } }); + }} onShare={() => setShareModal(q.uniqueLink!)} onDelete={() => { if (archiveAllowed(q)) { diff --git a/packages/frontend/src/pages/QuizPage.tsx b/packages/frontend/src/pages/QuizPage.tsx index 844d525..c464dad 100644 --- a/packages/frontend/src/pages/QuizPage.tsx +++ b/packages/frontend/src/pages/QuizPage.tsx @@ -63,6 +63,7 @@ export const QuizPage: React.FC = () => { const quizId: Id = state?.quizId; const activate = state?.activate; const start: boolean = state?.start ?? false; + const stop: boolean = state?.stop ?? false; const system = useActorSystem(); const [mbLocalUser] = useStatefulActor<{ user: User }>("LocalUser"); const [mbQuiz, tryQuizActor] = useStatefulActor("CurrentQuiz"); @@ -107,6 +108,9 @@ export const QuizPage: React.FC = () => { if (start) { setTimeout(() => q.send(q, CurrentQuizMessages.ChangeState("STARTED")), 500); } + if (stop) { + setTimeout(() => q.send(q, CurrentQuizMessages.ChangeState("STOPPED")), 500); + } }); }); }, [quizId, tryQuizActor.hasValue]); From 6af392f170d519ec6b8580824e289b0684468d1e Mon Sep 17 00:00:00 2001 From: "e.hagenkort" Date: Sun, 26 Jan 2025 22:06:53 +0100 Subject: [PATCH 50/51] Delete comment --- packages/frontend/src/components/quizzes-panel/QuizCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx index 6009e5d..a78ca92 100644 --- a/packages/frontend/src/components/quizzes-panel/QuizCard.tsx +++ b/packages/frontend/src/components/quizzes-panel/QuizCard.tsx @@ -120,7 +120,7 @@ export const QuizCard: React.FC<{ title={i18n._("quiz-card.button-tooltip.stop")} variant="primary" className="me-2" - onClick={onStop} // TODO: onStop + onClick={onStop} > From 4a8892ad4d701042d330e14585c34326795e9eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Han=C3=9F?= Date: Fri, 31 Jan 2025 12:27:16 +0100 Subject: [PATCH 51/51] Version bumb -> 1.6.1 --- packages/frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 62aa622..b4bb4e8 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -1,7 +1,7 @@ { "name": "@recapp/frontend", "private": true, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "scripts": { "dev": "vite",