diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/Form.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/Form.java index 052f9bcfdd20648f6754fa0c47764106f004df83..5667bba3f965d1ac26e1c5f12ccdc597df77d41d 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/Form.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/Form.java @@ -636,13 +636,16 @@ public class Form { * check if this is the FormItem to be dispatched */ Component tmp = fi.getComponent(); - String tmpD = FormBaseComponentIdProvider.DISPPREFIX + tmp.getDispatchID(); - - if (!foundDispatchItem && tmpD.equals(dispatchId)) { - dispatchFormItem = fi; - foundDispatchItem = true; + if(tmp != null) { + String tmpD = FormBaseComponentIdProvider.DISPPREFIX.concat(tmp.getDispatchID()); + if (!foundDispatchItem && tmpD.equals(dispatchId)) { + dispatchFormItem = fi; + foundDispatchItem = true; + } + } else { + log.warn("Null component: {}", fi); } - + /* * let the form item evaluate the form request, e.g. get out its data */ diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java index 3c9c8d470c27c0d752d81a109a6f9ced6a3f3087..14ea534e3b1e0dcb2837498a44fa6a66fbe97aa3 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java @@ -1923,11 +1923,17 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle rootFormAvailable(extendedSearchButton); rootFormAvailable(customTypeButton); rootFormAvailable(classicTypeButton); + if(components != null) { + for(FormItem item:components.values()) { + rootFormAvailable(item); + } + } } private final void rootFormAvailable(FormItem item) { - if(item != null && item.getRootForm() != getRootForm()) + if(item != null && item.getRootForm() != getRootForm()) { item.setRootForm(getRootForm()); + } } @Override diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java index 3923a777b3be96b891b450982bfd8cdd0a5fc2e0..c2f8cffff3a051d7d6ad4b6854c9bed89920f061 100644 --- a/src/main/java/org/olat/core/util/FileUtils.java +++ b/src/main/java/org/olat/core/util/FileUtils.java @@ -488,7 +488,7 @@ public class FileUtils { deleteFile(sourceFile); } } catch (IOException e) { - log.error("Could not copy file::" + sourceFile.getAbsolutePath() + " to file::" + targetFile.getAbsolutePath(), e); + log.error("Could not copy file::{} to file::{}", sourceFile.getAbsolutePath(), targetFile.getAbsolutePath(), e); return false; } return true; diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties index cc5e89bae060cc7349bbfff8394fbb008ffd015f..a9b49dc9f7bbc9b9b22ed43f2489fdf934c9e119 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties @@ -59,7 +59,7 @@ form.individual.assessment.docs=$org.olat.course.nodes.ms\:form.individual.asses form.error.date=Es muss ein Datum angegeben werden. form.error.scoreOutOfRange=$org.olat.course.assessment\:form.error.scoreOutOfRange form.error.wrongFloat=$org.olat.course.nodes.ms\:form.error.wrongFloat -fully.assessed.trigger.status.done=Status durch Betreuer auf "abgeschlosen" gesetzt. +fully.assessed.trigger.status.done=Status durch Betreuer auf "abgeschlossen" gesetzt. ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment info.title=$org.olat.course.nodes.ms\:info.title label=Beschriftung diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java index ab831cf0cc134a90b7dee70f1508dfa6dc33f30e..067a62afb4eee60071decf4e87f11b2c6153bc2e 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java @@ -35,6 +35,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import javax.persistence.CacheRetrieveMode; +import javax.persistence.CacheStoreMode; import javax.persistence.LockModeType; import javax.persistence.Query; @@ -1038,11 +1040,12 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { AssignmentResponse response; if(currentTask == null || !StringHelper.containsNonWhitespace(currentTask.getTaskName())) { - TaskList reloadedTasks = loadForUpdate(tasks); - File tasksFolder = getTasksDirectory(courseEnv, cNode); String[] taskFiles = tasksFolder.list(SystemFilenameFilter.FILES_ONLY); + + TaskList reloadedTasks = loadForUpdate(tasks); List<String> assignedFilenames = getAssignedTasks(reloadedTasks); + assignedFilenames.retainAll(List.of(taskFiles)); String taskName; if(GTACourseNode.GTASK_SAMPLING_UNIQUE.equals(cNode.getModuleConfiguration().get(GTACourseNode.GTASK_SAMPLING))) { @@ -1156,10 +1159,15 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { @Override public List<String> getAssignedTasks(TaskList taskList) { - return dbInstance.getCurrentEntityManager() + List<String> taskNames = dbInstance.getCurrentEntityManager() .createNamedQuery("tasksByTaskList", String.class) .setParameter("taskListKey", taskList.getKey()) + .setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS) + .setHint("javax.persistence.cache.storeMode", CacheStoreMode.BYPASS) .getResultList(); + return taskNames.stream() + .filter(name -> (StringHelper.containsNonWhitespace(name))) + .collect(Collectors.toList()); } @Override diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21EditLayoutForm.java b/src/main/java/org/olat/course/nodes/iq/QTI21EditLayoutForm.java index e3ac1ffc94ef0670ae1fcfc1bcc24ef3b0496848..17552c5666d29bbfd7176f4b35c7b5665c0144ef 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21EditLayoutForm.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21EditLayoutForm.java @@ -244,7 +244,7 @@ public class QTI21EditLayoutForm extends FormBasicController { displayScoreProgressEl.select(onKeys[0], true); } - boolean questionMaxScore = configRef ? deliveryOptions.isDisplayScoreProgress() : + boolean questionMaxScore = configRef ? deliveryOptions.isDisplayMaxScoreItem() : modConfig.getBooleanSafe(IQEditController.CONFIG_KEY_QUESTION_MAX_SCORE, deliveryOptions.isDisplayMaxScoreItem()); displayMaxScoreItemEl = uifactory.addCheckboxesHorizontal("scoreMaxItem", "qti.form.max.score.item", formLayout, onKeys, onValues); displayMaxScoreItemEl.setEnabled(!configRef); diff --git a/src/main/java/org/olat/course/nodes/survey/SurveyManager.java b/src/main/java/org/olat/course/nodes/survey/SurveyManager.java index ff6660e0534bd9c9d435cc7e01df6c36126ebc87..14de2bcbad13f875e287a1121619d78b04772afd 100644 --- a/src/main/java/org/olat/course/nodes/survey/SurveyManager.java +++ b/src/main/java/org/olat/course/nodes/survey/SurveyManager.java @@ -30,6 +30,7 @@ import org.olat.modules.forms.EvaluationFormParticipation; import org.olat.modules.forms.EvaluationFormSession; import org.olat.modules.forms.EvaluationFormSurvey; import org.olat.modules.forms.EvaluationFormSurveyIdentifier; +import org.olat.modules.forms.SessionFilter; import org.olat.modules.forms.model.xml.Form; import org.olat.repository.RepositoryEntry; @@ -69,8 +70,8 @@ public interface SurveyManager { public void onExecutionFinished(SurveyCourseNode courseNode, UserCourseEnvironment userCourseEnv); - public long getCountOfSessions(EvaluationFormSurvey survey); - + public Long getSessionsCount(SessionFilter filter); + public void deleteAllData(EvaluationFormSurvey survey, SurveyCourseNode courseNode, UserCourseEnvironment userCourseEnv); } diff --git a/src/main/java/org/olat/course/nodes/survey/manager/SurveyManagerImpl.java b/src/main/java/org/olat/course/nodes/survey/manager/SurveyManagerImpl.java index 645000326f78403449fd15555f977bcb0fa32537..fe79d2fd4b71cb5d2340193bcfe30c955bedadfc 100644 --- a/src/main/java/org/olat/course/nodes/survey/manager/SurveyManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/survey/manager/SurveyManagerImpl.java @@ -43,6 +43,7 @@ import org.olat.modules.forms.EvaluationFormParticipationIdentifier; import org.olat.modules.forms.EvaluationFormSession; import org.olat.modules.forms.EvaluationFormSurvey; import org.olat.modules.forms.EvaluationFormSurveyIdentifier; +import org.olat.modules.forms.SessionFilter; import org.olat.modules.forms.model.xml.Form; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -176,8 +177,8 @@ public class SurveyManagerImpl implements SurveyManager { } @Override - public long getCountOfSessions(EvaluationFormSurvey survey) { - return evaluationFormManager.getCountOfSessions(survey); + public Long getSessionsCount(SessionFilter filter) { + return evaluationFormManager.loadSessionsCount(filter); } @Override diff --git a/src/main/java/org/olat/course/nodes/survey/ui/SurveyDeleteDataConfirmationController.java b/src/main/java/org/olat/course/nodes/survey/ui/SurveyDeleteDataConfirmationController.java index d2dff8ce746013d536553fee9167698896d0e0db..557a58cd01fa72b41377682316cf5e5ba6984171 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/SurveyDeleteDataConfirmationController.java +++ b/src/main/java/org/olat/course/nodes/survey/ui/SurveyDeleteDataConfirmationController.java @@ -40,11 +40,13 @@ public class SurveyDeleteDataConfirmationController extends FormBasicController private MultipleSelectionElement confirmationEl; - private final long numberOfSessions; + private final Long allSessions; + private final Long doneSessions; - public SurveyDeleteDataConfirmationController(UserRequest ureq, WindowControl wControl, long numberOfSessions) { + public SurveyDeleteDataConfirmationController(UserRequest ureq, WindowControl wControl, Long allSessions, Long doneSessions) { super(ureq, wControl, "delete_data_confirmation"); - this.numberOfSessions = numberOfSessions; + this.allSessions = allSessions; + this.doneSessions = doneSessions; initForm(ureq); } @@ -54,7 +56,8 @@ public class SurveyDeleteDataConfirmationController extends FormBasicController formLayout.add("confirm", confirmCont); confirmCont.setRootForm(mainForm); - flc.contextPut("numSessions", String.valueOf(numberOfSessions)); + String message = translate("run.command.delete.data.all.message", new String[] {String.valueOf(allSessions), String.valueOf(doneSessions)} ); + flc.contextPut("message", message); String[] conformationValues = new String[] { translate("run.command.delete.data.all.check") }; confirmationEl = uifactory.addCheckboxesHorizontal("confirm.delete", "", confirmCont, confirmationKeys, conformationValues); diff --git a/src/main/java/org/olat/course/nodes/survey/ui/SurveyRunController.java b/src/main/java/org/olat/course/nodes/survey/ui/SurveyRunController.java index 4b3efbce6ae261d56a554392072cdb314ab6bafa..4c6b667705b70c8a737f85dc4be592243a13caa8 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/SurveyRunController.java +++ b/src/main/java/org/olat/course/nodes/survey/ui/SurveyRunController.java @@ -42,6 +42,7 @@ import org.olat.modules.forms.EvaluationFormParticipation; import org.olat.modules.forms.EvaluationFormSession; import org.olat.modules.forms.EvaluationFormSurvey; import org.olat.modules.forms.EvaluationFormSurveyIdentifier; +import org.olat.modules.forms.SessionFilterFactory; import org.olat.modules.forms.ui.EvaluationFormExecutionController; import org.olat.modules.forms.ui.ProgressEvent; import org.olat.repository.RepositoryEntry; @@ -180,8 +181,9 @@ public class SurveyRunController extends BasicController { } private void doConfirmDeleteAllData(UserRequest ureq) { - long countOfSessions = surveyManager.getCountOfSessions(survey); - deleteDataConfirmationCtrl = new SurveyDeleteDataConfirmationController(ureq, getWindowControl(), countOfSessions); + Long allSessions = surveyManager.getSessionsCount(SessionFilterFactory.create(survey)); + Long doneSessions = surveyManager.getSessionsCount(SessionFilterFactory.createSelectDone(survey)); + deleteDataConfirmationCtrl = new SurveyDeleteDataConfirmationController(ureq, getWindowControl(), allSessions, doneSessions); listenTo(deleteDataConfirmationCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), deleteDataConfirmationCtrl.getInitialComponent(), true, translate("run.command.delete.data.all.title"), true); diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_content/delete_data_confirmation.html b/src/main/java/org/olat/course/nodes/survey/ui/_content/delete_data_confirmation.html index 124c56a8b3a0a6d6bcb6ae8cc36dbef083b7ddfb..47f005503974c3a20fb58b2cbf9a14b3665b52f6 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_content/delete_data_confirmation.html +++ b/src/main/java/org/olat/course/nodes/survey/ui/_content/delete_data_confirmation.html @@ -1,4 +1,4 @@ <div class="o_error"> - $r.translate("run.command.delete.data.all.message", $numSessions) + $message </div> $r.render("confirm") \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_de.properties index 56d4753a81a90b5ee40a1fd20ba7f389d0309749..965a3461de6648bbedea6bc104c5e343ed6644a8 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_de.properties @@ -31,7 +31,7 @@ run.command.delete.data.all=Umfrage zur\u00fcksetzen run.command.delete.data.all.confirmation.error=Best\u00e4tigen Sie bitte das L\u00f6schen. run.command.delete.data.all.button=L\u00f6schen run.command.delete.data.all.check=Alle Antworten l\u00f6schen -run.command.delete.data.all.message=Wollen Sie wirklich alle Antworten l\u00f6schen? Es haben bereits {0} Benutzer/innen an dieser Umfrage teilgenommen. Die Antworten k\u00f6nnen nicht wieder hergestellt werden! +run.command.delete.data.all.message=Wollen Sie wirklich alle Antworten l\u00f6schen? Die Umfrage wurde bereits von {0} Benutzer/innen gestartet und von {1} Benutzer/innen abgeschlossen. Die Antworten k\u00f6nnen nicht wieder hergestellt werden! run.command.delete.data.all.title=Alle Antworten l\u00f6schen run.participation.done.message=Sie haben den Fragebogen bereits ausgef\u00fcllt. Vielen Dank f\u00fcr Ihre Teilnahme. run.participation.done.title=Fragebogen ausgef\u00fcllt diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_en.properties index 56e0442448ccbd3b5f58881f173a8ecc6c24c07d..61967e710cfd6ee4f9118d6da65afce1b5041734 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_en.properties @@ -31,7 +31,7 @@ run.command.delete.data.all=Reset survey run.command.delete.data.all.confirmation.error=Please confirm the deletion of the responses. run.command.delete.data.all.button=Delete run.command.delete.data.all.check=Delete all responses -run.command.delete.data.all.message=Do you really want to delete all responses. Already {0} users participated in this survey. It is not possible to restore the responses. +run.command.delete.data.all.message=Do you really want to delete all responses. The survey has already been started by {0} users and completed by {1} users. It is not possible to restore the responses. run.command.delete.data.all.title=Delete all responses run.participation.done.message=You have already finished this survey. Thank you for your participation. run.participation.done.title=Survey finished diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_fr.properties index ee9f8a53adc59b6c1d24820f101d7f1e2a1c7557..da6b9f47a86e48ae3396fbc0761aeab44f3e3a80 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_fr.properties @@ -1,45 +1,44 @@ #Thu Oct 08 13:56:14 CEST 2020 -condition.accessibility.title=Acc\u00E8s +condition.accessibility.title=Acc\u00e8s course.node.link.text=Questionnaire -edit.choose=Choisir, cr\u00E9er ou importer +edit.choose=Choisir, cr\u00e9er ou importer edit.choose.evaluation.form=Choisir un questionnaire edit.edit=Editer edit.evaluation.form=Questionnaire edit.evaluation.form.link={0} -edit.evaluation.form.not.choosen=Pas de questionnaire s\u00E9lectionner +edit.evaluation.form.not.choosen=Pas de questionnaire s\u00e9lectionner edit.execution=Participation par edit.execution.by.coach=Coaches -edit.execution.by.guest=Invit\u00E9s -edit.execution.by.owner=Propri\u00E9taires +edit.execution.by.guest=Invit\u00e9s +edit.execution.by.owner=Propri\u00e9taires edit.execution.by.participant=Participants -edit.preview=Aper\u00E7u +edit.preview=Aper\u00e7u edit.replace=Remplacer -edit.report=R\u00E9sultats visible pour +edit.report=R\u00e9sultats visible pour edit.report.for.coach=Coaches -edit.report.for.guest=Invit\u00E9s -edit.report.for.owner=Propri\u00E9taires +edit.report.for.guest=Invit\u00e9s +edit.report.for.owner=Propri\u00e9taires edit.report.for.participant=Participants edit.title=Questionnaire -error.repo.entry.missing=Le questionnaire que vous voulez afficher \u00E0 \u00E9t\u00E9 effac\u00E9 entre-temps des ressources didactiques. -error.repo.entry.not.replaceable=Le questionnaire ne peut plus \u00EAtre remplac\u00E9. -error.repo.no.key.long=Pour "{0}", vous devez s\u00E9lectionner un questionnaire dans le tab "Questionnaire" dans la section configuration. -error.repo.no.key.short=Pas de questionnaire s\u00E9lectionn\u00E9. +error.repo.entry.missing=Le questionnaire que vous voulez afficher \u00e0 \u00e9t\u00e9 effac\u00e9 entre-temps des ressources didactiques. +error.repo.entry.not.replaceable=Le questionnaire ne peut plus \u00eatre remplac\u00e9. +error.repo.no.key.long=Pour "{0}", vous devez s\u00e9lectionner un questionnaire dans le tab "Questionnaire" dans la section configuration. +error.repo.no.key.short=Pas de questionnaire s\u00e9lectionn\u00e9. figure.course=Cours -figure.course.node=\u00C9lement de cours +figure.course.node=\u00c9lement de cours fully.assessed.trigger.status.done=Questionnaire soumis -pane.tab.accessibility=Acc\u00E8s +pane.tab.accessibility=Acc\u00e8s pane.tab.config=Questionnaire -report.noaccess=Vous n'avez pas acc\u00E8s aux statistiques de ce questionnaire. Soit vous n'avez pas les autorisations requises, soit vous n'avez pas termin\u00E9 de remplir le questionnaire. -run.command.delete.data.all=R\u00E9initialiser le questionnaire +report.noaccess=Vous n'avez pas acc\u00e8s aux statistiques de ce questionnaire. Soit vous n'avez pas les autorisations requises, soit vous n'avez pas termin\u00e9 de remplir le questionnaire. +run.command.delete.data.all=R\u00e9initialiser le questionnaire run.command.delete.data.all.button=Effacer -run.command.delete.data.all.check=Effacer toutes les r\u00E9ponses -run.command.delete.data.all.confirmation.error=Veuillez confirmer l'effacement de toutes les r\u00E9ponses. -run.command.delete.data.all.message=Voulez-vous vraiment effacer toutes les r\u00E9ponses de ce questionnaire? {0} utilisateurs l'ont d\u00E9j\u00E0 rempli. Il ne sera pas possible de restaurer les r\u00E9ponses effac\u00E9es. -run.command.delete.data.all.title=Effacer toutes les r\u00E9ponses -run.no.survey.message=Le questionnaire n'est pas pr\u00EAt \u00E0 \u00EAtre utilis\u00E9. -run.no.survey.title=Le questionnaire n'est pas pr\u00EAt. +run.command.delete.data.all.check=Effacer toutes les r\u00e9ponses +run.command.delete.data.all.confirmation.error=Veuillez confirmer l'effacement de toutes les r\u00e9ponses. +run.command.delete.data.all.title=Effacer toutes les r\u00e9ponses +run.no.survey.message=Le questionnaire n'est pas pr\u00eat \u00e0 \u00eatre utilis\u00e9. +run.no.survey.title=Le questionnaire n'est pas pr\u00eat. run.noaccess.message=Cette partie du cours ne vous est pas accessible. -run.noaccess.title=Acc\u00E8s refus\u00E9 -run.participation.done.message=Vous avez d\u00E9j\u00E0 rempli ce questionnaire. Merci de votre participation. -run.participation.done.title=Questionnaire termin\u00E9 -run.reset=R\u00E9initialiser +run.noaccess.title=Acc\u00e8s refus\u00e9 +run.participation.done.message=Vous avez d\u00e9j\u00e0 rempli ce questionnaire. Merci de votre participation. +run.participation.done.title=Questionnaire termin\u00e9 +run.reset=R\u00e9initialiser diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_it.properties index b45b426ceb8f6724ea3d78a68e326d7415150569..1e2bb64785e0927d916da2f1990122b8e686ff74 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_it.properties @@ -19,8 +19,8 @@ edit.report.for.guest=Ospiti edit.report.for.owner=Proprietari edit.report.for.participant=Partecipanti edit.title=Indagine -error.repo.entry.missing=Questa indagine \u00E8 stata nel frattempo cancellata all'interno della cartella di memorizzazione delle risorse di apprendimento. -error.repo.entry.not.replaceable=Il questionario non pu\u00F2 pi\u00F9 essere sostituito. +error.repo.entry.missing=Questa indagine \u00e8 stata nel frattempo cancellata all'interno della cartella di memorizzazione delle risorse di apprendimento. +error.repo.entry.not.replaceable=Il questionario non pu\u00f2 pi\u00f9 essere sostituito. error.repo.no.key.long=Per "{0}" devi selezionare un questionario nella scheda " Indagine" all'interno della sezione di configurazione. error.repo.no.key.short=Nessun questionario scelto. fully.assessed.trigger.status.done=Indagine terminata @@ -30,12 +30,11 @@ run.command.delete.data.all=Resettare indagine run.command.delete.data.all.button=Cancellare run.command.delete.data.all.check=Cancellare tutte le risposte run.command.delete.data.all.confirmation.error=Si prega di confermare la cancellazione delle risposte. -run.command.delete.data.all.message=Vuole davvero cancellare tutte le risposte? Gi\u00E0 {0} utenti hanno partecipato a questa indagine. Non \u00E8 possibile ripristinare le risposte. run.command.delete.data.all.title=Cancellare tutte le risposte -run.no.survey.message=Questa indagine non \u00E8 disponibile per la partecipazione. +run.no.survey.message=Questa indagine non \u00e8 disponibile per la partecipazione. run.no.survey.title=Indagine non pronta -run.noaccess.message=Questa parte del corso non \u00E8 accessibile per lei. +run.noaccess.message=Questa parte del corso non \u00e8 accessibile per lei. run.noaccess.title=Nessuno accesso -run.participation.done.message=Lei ha gi\u00E0 terminato questo sondaggio. Grazie per la sua partecipazione. +run.participation.done.message=Lei ha gi\u00e0 terminato questo sondaggio. Grazie per la sua partecipazione. run.participation.done.title=Indagine terminata run.reset=Resettare diff --git a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_pt_BR.properties index dedcf67ac3c5ee55df023b2db5c07531af57acd0..c50631bab21dfd0359b19ce8d378fa20d06a9b46 100644 --- a/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/nodes/survey/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,43 +1,42 @@ #Fri Sep 25 19:50:24 CEST 2020 course.node.link.text=Pesquisa edit.choose=Escolha, crie ou importe -edit.choose.evaluation.form=Escolha o question\u00E1rio +edit.choose.evaluation.form=Escolha o question\u00e1rio edit.edit=Editar -edit.evaluation.form=Question\u00E1rio +edit.evaluation.form=Question\u00e1rio edit.evaluation.form.link={0} -edit.evaluation.form.not.choosen=Nenhum question\u00E1rio escolhido -edit.execution=Participa\u00E7\u00E3o por +edit.evaluation.form.not.choosen=Nenhum question\u00e1rio escolhido +edit.execution=Participa\u00e7\u00e3o por edit.execution.by.coach=Treinadores edit.execution.by.guest=Convidados -edit.execution.by.owner=Propriet\u00E1rios +edit.execution.by.owner=Propriet\u00e1rios edit.execution.by.participant=Participantes edit.preview=Visualizar edit.replace=Substituir -edit.report=Resultados vis\u00EDveis para +edit.report=Resultados vis\u00edveis para edit.report.for.coach=Treinadores edit.report.for.guest=Convidados -edit.report.for.owner=Propriet\u00E1rios +edit.report.for.owner=Propriet\u00e1rios edit.report.for.participant=Participantes edit.title=Pesquisa -error.repo.entry.missing=Esta pesquisa foi apagada enquanto isso dentro da pasta de armazenamento de recursos did\u00E1ticos. -error.repo.entry.not.replaceable=O question\u00E1rio n\u00E3o pode mais ser substitu\u00EDdo. -error.repo.no.key.long=Para "{0}" voc\u00EA tem que selecionar um question\u00E1rio na aba "Pesquisa" dentro da se\u00E7\u00E3o de configura\u00E7\u00E3o. -error.repo.no.key.short=Nenhum question\u00E1rio escolhido. +error.repo.entry.missing=Esta pesquisa foi apagada enquanto isso dentro da pasta de armazenamento de recursos did\u00e1ticos. +error.repo.entry.not.replaceable=O question\u00e1rio n\u00e3o pode mais ser substitu\u00eddo. +error.repo.no.key.long=Para "{0}" voc\u00ea tem que selecionar um question\u00e1rio na aba "Pesquisa" dentro da se\u00e7\u00e3o de configura\u00e7\u00e3o. +error.repo.no.key.short=Nenhum question\u00e1rio escolhido. figure.course=Curso figure.course.node=Elemento do Curso -fully.assessed.trigger.status.done=Pesquisa conclu\u00EDda +fully.assessed.trigger.status.done=Pesquisa conclu\u00edda pane.tab.config=Pesquisa -report.noaccess=Voc\u00EA n\u00E3o tem acesso \u00E0s estat\u00EDsticas desta pesquisa. Voc\u00EA n\u00E3o tem os direitos necess\u00E1rios ou n\u00E3o terminou sua participa\u00E7\u00E3o. +report.noaccess=Voc\u00ea n\u00e3o tem acesso \u00e0s estat\u00edsticas desta pesquisa. Voc\u00ea n\u00e3o tem os direitos necess\u00e1rios ou n\u00e3o terminou sua participa\u00e7\u00e3o. run.command.delete.data.all=Redefinir pesquisa run.command.delete.data.all.button=Excluir run.command.delete.data.all.check=Excluir todas as respostas -run.command.delete.data.all.confirmation.error=Por favor, confirme a exclus\u00E3o das respostas. -run.command.delete.data.all.message=Voc\u00EA realmente deseja excluir todas as respostas? {0} usu\u00E1rios j\u00E1 participaram desta pesquisa. N\u00E3o \u00E9 poss\u00EDvel restaurar as respostas. +run.command.delete.data.all.confirmation.error=Por favor, confirme a exclus\u00e3o das respostas. run.command.delete.data.all.title=Excluir todas as respostas -run.no.survey.message=A pesquisa n\u00E3o est\u00E1 pronta para participar. -run.no.survey.title=Pesquisa n\u00E3o est\u00E1 pronta -run.noaccess.message=Esta parte do curso n\u00E3o est\u00E1 acess\u00EDvel para voc\u00EA. +run.no.survey.message=A pesquisa n\u00e3o est\u00e1 pronta para participar. +run.no.survey.title=Pesquisa n\u00e3o est\u00e1 pronta +run.noaccess.message=Esta parte do curso n\u00e3o est\u00e1 acess\u00edvel para voc\u00ea. run.noaccess.title=Sem acesso -run.participation.done.message=Voc\u00EA j\u00E1 terminou esta pesquisa. Obrigado pela sua participa\u00E7\u00E3o. -run.participation.done.title=Pesquisa conclu\u00EDda +run.participation.done.message=Voc\u00ea j\u00e1 terminou esta pesquisa. Obrigado pela sua participa\u00e7\u00e3o. +run.participation.done.title=Pesquisa conclu\u00edda run.reset=Redefinir diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java index 858f9b2615b55a991a76c355493e5ec59074b2c5..bcbfafe069934b4f943b74ac02aec47ecc5cadfc 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java @@ -101,6 +101,9 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen private final boolean moderatorStartMeeting; private final OLATResourceable meetingOres; + private boolean withTools = false; + private boolean withPublish = false; + private FormLink joinButton; private FormLink uploadButton; private FormLink guestJoinButton; @@ -261,10 +264,12 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen if(administrator) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BRecordingsCols.publish)); + withPublish = true; if(recordingsHandler.canDeleteRecordings() && recordingsHandler.allowPermanentRecordings()) { DefaultFlexiColumnModel toolsCol = new DefaultFlexiColumnModel(BRecordingsCols.tools); toolsCol.setIconHeader("o_icon o_icon_actions o_icon-lg"); columnsModel.addFlexiColumnModel(toolsCol); + withTools = true; } else if(recordingsHandler.canDeleteRecordings()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete")); } @@ -297,18 +302,22 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen boolean pusblished = isPublishedForMe(recording.getReference(), attendee); BigBlueButtonRecordingRow row = new BigBlueButtonRecordingRow(recording, pusblished); if(administrator || moderator) { - String recId = recording.getRecording().getRecordId().toString(); - FormLink publishLink = uifactory.addFormLink("publish-".concat(recId), - "publish", "publish.recording", tableEl); - row.setPublishLink(publishLink); - publishLink.setUserObject(row); + String recId = recording.getRecording().getRecordId(); + if(withPublish) { + FormLink publishLink = uifactory.addFormLink("publish-".concat(recId), + "publish", "publish.recording", tableEl); + row.setPublishLink(publishLink); + publishLink.setUserObject(row); + } - FormLink toolsLink = uifactory.addFormLink("tools-".concat(recId), - "tools", "", tableEl, Link.LINK | Link.NONTRANSLATED); - toolsLink.setAriaLabel(translate("table.header.actions")); - toolsLink.setIconRightCSS("o_icon o_icon_actions o_icon-lg"); - toolsLink.setUserObject(row); - row.setToolsLink(toolsLink); + if(withTools) { + FormLink toolsLink = uifactory.addFormLink("tools-".concat(recId), + "tools", "", tableEl, Link.LINK | Link.NONTRANSLATED); + toolsLink.setAriaLabel(translate("table.header.actions")); + toolsLink.setIconRightCSS("o_icon o_icon_actions o_icon-lg"); + toolsLink.setUserObject(row); + row.setToolsLink(toolsLink); + } } return row; } diff --git a/src/main/java/org/olat/modules/forms/EvaluationFormManager.java b/src/main/java/org/olat/modules/forms/EvaluationFormManager.java index 7040f63670449bcce9347318935438aa2f8c7330..bdb7e1a782c413376613e336c4fe974814b5a3d3 100644 --- a/src/main/java/org/olat/modules/forms/EvaluationFormManager.java +++ b/src/main/java/org/olat/modules/forms/EvaluationFormManager.java @@ -176,8 +176,6 @@ public interface EvaluationFormManager { */ public EvaluationFormSession reopenSession(EvaluationFormSession session); - public long getCountOfSessions(EvaluationFormSurveyRef surveyRef); - public List<EvaluationFormResponse> getResponses(List<String> responseIdentifiers, SessionFilter filter, Limit limit); public EvaluationFormResponse createStringResponse(String responseIdentifier, EvaluationFormSession session, diff --git a/src/main/java/org/olat/modules/forms/SessionFilterFactory.java b/src/main/java/org/olat/modules/forms/SessionFilterFactory.java index f6ae46461c294e1289e5db458a167df250a07919..ff23376d0a1a947d8bf294b69802a16d57dbc1be 100644 --- a/src/main/java/org/olat/modules/forms/SessionFilterFactory.java +++ b/src/main/java/org/olat/modules/forms/SessionFilterFactory.java @@ -51,6 +51,10 @@ public class SessionFilterFactory { EvaluationFormSessionStatus status) { return new SurveysFilter(surveyIdentitfier, status); } + + public static SessionFilter create(EvaluationFormSurveyRef survey) { + return new SurveysFilter(Collections.singletonList(survey)); + } public static SessionFilter createSelectDone(EvaluationFormSurveyRef survey) { return createSelectDone(Collections.singletonList(survey)); diff --git a/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java b/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java index 3b37dc2ab2ba1f124d983fd33f469786d3867f66..31715c1762be393f0564c4e0940f6f869a1b3add 100644 --- a/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java +++ b/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java @@ -361,11 +361,6 @@ public class EvaluationFormManagerImpl implements EvaluationFormManager { return finishedSesssion; } - @Override - public long getCountOfSessions(EvaluationFormSurveyRef surveyRef) { - return evaluationFormSessionDao.getCountOfSessions(surveyRef); - } - @Override public EvaluationFormResponse createFileResponse(String responseIdentifier, EvaluationFormSession session, File file, String filename) throws IOException { diff --git a/src/main/java/org/olat/modules/forms/manager/EvaluationFormSessionDAO.java b/src/main/java/org/olat/modules/forms/manager/EvaluationFormSessionDAO.java index 68c000b9c50ecd3bc201758966a7bd027bd20a19..b237c3aee0ac741e5077c754ece9255dce57b662 100644 --- a/src/main/java/org/olat/modules/forms/manager/EvaluationFormSessionDAO.java +++ b/src/main/java/org/olat/modules/forms/manager/EvaluationFormSessionDAO.java @@ -228,20 +228,6 @@ class EvaluationFormSessionDAO { } return session; } - - long getCountOfSessions(EvaluationFormSurveyRef surveyRef) { - if (surveyRef == null) return 0; - - StringBuilder sb = new StringBuilder(); - sb.append("select count(session.key) from evaluationformsession as session"); - sb.append(" where session.survey.key=:surveyKey"); - - List<Long> counts = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), Long.class) - .setParameter("surveyKey", surveyRef.getKey()) - .getResultList(); - return counts.get(0); - } void deleteSessions(EvaluationFormSurveyRef surveyRef) { if (surveyRef == null) return; diff --git a/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java b/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java index 989b5d22d85ae1ee1732ec600b5fd22191a2eff1..704e676ee94e43c6a65a0dc51c39df7debe77c51 100644 --- a/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java +++ b/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java @@ -19,21 +19,29 @@ */ package org.olat.course.nodes.gta.manager; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.logging.log4j.Logger; import org.junit.Assert; import org.junit.Test; import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; import org.olat.core.util.nodes.INode; import org.olat.course.CourseFactory; import org.olat.course.ICourse; @@ -41,12 +49,14 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.AssignmentResponse; import org.olat.course.nodes.gta.AssignmentResponse.Status; +import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; import org.olat.course.nodes.gta.TaskProcess; import org.olat.course.nodes.gta.TaskRevisionDate; import org.olat.course.nodes.gta.model.TaskListImpl; +import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.manager.BusinessGroupDAO; @@ -914,6 +924,311 @@ public class GTAManagerTest extends OlatTestCase { Assert.assertEquals(TaskProcess.correction, loadedTaskRevision.getTaskStatus()); } + @Test + public void assignTaskAutomatically() { + //prepare + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_SAMPLING, GTACourseNode.GTASK_SAMPLING_REUSE); + TaskList tasks = gtaManager.createIfNotExists(re, node); + + CourseEnvironment courseEnv = CourseFactory.loadCourse(re).getCourseEnvironment(); + File tasksDirectory = gtaManager.getTasksDirectory(courseEnv, node); + FileUtils.deleteDirsAndFiles(tasksDirectory, true, false); + copyTestFile(tasksDirectory, "File00O.pdf"); + copyTestFile(tasksDirectory, "File0O0.pdf"); + copyTestFile(tasksDirectory, "FileO00.pdf"); + dbInstance.commit(); + + //select + AssignmentResponse response = gtaManager.assignTaskAutomatically(tasks, participant, courseEnv, node); + dbInstance.commitAndCloseSession(); + //check + Assert.assertNotNull(response); + Assert.assertNotNull(response.getTask()); + Assert.assertEquals(AssignmentResponse.Status.ok, response.getStatus()); + + Task task = response.getTask(); + Assert.assertNotNull(task.getKey()); + Assert.assertNull(task.getBusinessGroup()); + Assert.assertNotNull(task.getCreationDate()); + Assert.assertNotNull(task.getLastModified()); + Assert.assertEquals(tasks, task.getTaskList()); + Assert.assertEquals(participant, task.getIdentity()); + assertThat(task.getTaskName()) + .isIn("File00O.pdf", "File0O0.pdf", "FileO00.pdf"); + } + + @Test + public void assignTaskAutomaticallyHighload() { + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_SAMPLING, GTACourseNode.GTASK_SAMPLING_REUSE); + TaskList tasks = gtaManager.createIfNotExists(re, node); + + CourseEnvironment courseEnv = CourseFactory.loadCourse(re).getCourseEnvironment(); + File tasksDirectory = gtaManager.getTasksDirectory(courseEnv, node); + FileUtils.deleteDirsAndFiles(tasksDirectory, true, false); + copyTestFile(tasksDirectory, "File00O.pdf"); + copyTestFile(tasksDirectory, "File0O0.pdf"); + copyTestFile(tasksDirectory, "FileO00.pdf"); + copyTestFile(tasksDirectory, "FileOO0.pdf"); + copyTestFile(tasksDirectory, "FileO0O.pdf"); + dbInstance.commit(); + + final int numThreads = 25; + final int batchSize = 10; + final int numOfPersons = batchSize * numThreads; + List<Identity> participants = new ArrayList<>(numOfPersons); + for(int i=0; i<numOfPersons; i++) { + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-high-load-" + i); + participants.add(participant); + } + + CountDownLatch latch = new CountDownLatch(numThreads); + AssignThread[] threads = new AssignThread[numThreads]; + for(int i=0; i<threads.length;i++) { + List<Identity> batch = participants.subList(i * batchSize, (i + 1) * batchSize); + threads[i] = new AssignThread(batch, tasks, node, courseEnv, gtaManager, latch); + } + + for(int i=0; i<threads.length;i++) { + threads[i].start(); + } + + try { + latch.await(60, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Assert.fail("Takes too long (more than 120sec)"); + } + + int countErrors = 0; + for(int i=0; i<threads.length;i++) { + countErrors += threads[i].getErrors(); + } + Assert.assertEquals(0, countErrors); + + List<Task> taskList = gtaManager.getTasks(tasks, node); + Map<String, AtomicInteger> maps = Map.of("File00O.pdf", new AtomicInteger(0), "File0O0.pdf", new AtomicInteger(0), "FileO00.pdf", new AtomicInteger(0), + "FileOO0.pdf", new AtomicInteger(0), "FileO0O.pdf", new AtomicInteger(0)); + for(Task task:taskList) { + maps.get(task.getTaskName()).incrementAndGet(); + } + + Assert.assertEquals(5, maps.size()); + for(AtomicInteger count:maps.values()) { + log.info("Counter: {}", count.get()); + Assert.assertEquals(50, count.get()); + } + } + + @Test + public void assignTaskAutomaticallyHighloadPreload() { + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_SAMPLING, GTACourseNode.GTASK_SAMPLING_REUSE); + TaskList tasks = gtaManager.createIfNotExists(re, node); + + CourseEnvironment courseEnv = CourseFactory.loadCourse(re).getCourseEnvironment(); + File tasksDirectory = gtaManager.getTasksDirectory(courseEnv, node); + FileUtils.deleteDirsAndFiles(tasksDirectory, true, false); + copyTestFile(tasksDirectory, "File00O.pdf"); + copyTestFile(tasksDirectory, "File0O0.pdf"); + copyTestFile(tasksDirectory, "FileO00.pdf"); + dbInstance.commit(); + + final int numThreads = 12; + final int batchSize = 10; + final int numOfPersons = batchSize * numThreads; + List<Identity> participants = new ArrayList<>(numOfPersons); + for(int i=0; i<numOfPersons; i++) { + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-high-load-" + i); + participants.add(participant); + gtaManager.createAndPersistTask(null, tasks, TaskProcess.assignment, null, participant, node); + if(i % 10 == 0) { + dbInstance.commitAndCloseSession(); + } + } + dbInstance.commitAndCloseSession(); + + CountDownLatch latch = new CountDownLatch(numThreads); + AssignThread[] threads = new AssignThread[numThreads]; + for(int i=0; i<threads.length;i++) { + List<Identity> batch = participants.subList(i * batchSize, (i + 1) * batchSize); + threads[i] = new AssignThread(batch, tasks, node, courseEnv, gtaManager, latch); + } + + for(int i=0; i<threads.length;i++) { + threads[i].start(); + } + + try { + latch.await(60, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Assert.fail("Takes too long (more than 60sec)"); + } + + int countErrors = 0; + for(int i=0; i<threads.length;i++) { + countErrors += threads[i].getErrors(); + } + Assert.assertEquals(0, countErrors); + + List<Task> taskList = gtaManager.getTasks(tasks, node); + Map<String, AtomicInteger> maps = Map.of("File00O.pdf", new AtomicInteger(0), "File0O0.pdf", new AtomicInteger(0), "FileO00.pdf", new AtomicInteger(0)); + for(Task task:taskList) { + maps.get(task.getTaskName()).incrementAndGet(); + } + + Assert.assertEquals(3, maps.size()); + for(AtomicInteger count:maps.values()) { + log.info("Counter: {}", count.get()); + } + for(AtomicInteger count:maps.values()) { + Assert.assertEquals(numOfPersons / maps.size(), count.get()); + } + } + + @Test + public void assignTaskAutomaticallyDeletedFile() { + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_SAMPLING, GTACourseNode.GTASK_SAMPLING_REUSE); + TaskList tasks = gtaManager.createIfNotExists(re, node); + + CourseEnvironment courseEnv = CourseFactory.loadCourse(re).getCourseEnvironment(); + File tasksDirectory = gtaManager.getTasksDirectory(courseEnv, node); + FileUtils.deleteDirsAndFiles(tasksDirectory, true, false); + copyTestFile(tasksDirectory, "File00O.pdf"); + copyTestFile(tasksDirectory, "File0O0.pdf"); + copyTestFile(tasksDirectory, "FileO00.pdf"); + dbInstance.commit(); + + for(int i=0; i<10; i++) { + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-high-load-" + i); + String name = "File" + (i % 5) + ".pdf"; + gtaManager.createAndPersistTask(name, tasks, TaskProcess.assignment, null, participant, node); + if(i % 10 == 0) { + dbInstance.commitAndCloseSession(); + } + } + + final int numThreads = 3; + final int batchSize = 3; + final int numOfPersons = batchSize * numThreads; + List<Identity> participants = new ArrayList<>(numOfPersons); + for(int i=0; i<numOfPersons; i++) { + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-high-load-" + i); + participants.add(participant); + gtaManager.createAndPersistTask(null, tasks, TaskProcess.assignment, null, participant, node); + if(i % 10 == 0) { + dbInstance.commitAndCloseSession(); + } + } + dbInstance.commitAndCloseSession(); + + CountDownLatch latch = new CountDownLatch(numThreads); + AssignThread[] threads = new AssignThread[numThreads]; + for(int i=0; i<threads.length;i++) { + List<Identity> batch = participants.subList(i * batchSize, (i + 1) * batchSize); + threads[i] = new AssignThread(batch, tasks, node, courseEnv, gtaManager, latch); + } + + for(int i=0; i<threads.length;i++) { + threads[i].start(); + } + + try { + latch.await(60, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Assert.fail("Takes too long (more than 120sec)"); + } + + int countErrors = 0; + for(int i=0; i<threads.length;i++) { + countErrors += threads[i].getErrors(); + } + Assert.assertEquals(0, countErrors); + + List<Task> taskList = gtaManager.getTasks(tasks, node); + Map<String, AtomicInteger> maps = Map.of("File00O.pdf", new AtomicInteger(0), "File0O0.pdf", new AtomicInteger(0), "FileO00.pdf", new AtomicInteger(0)); + for(Task task:taskList) { + if(maps.containsKey(task.getTaskName())) { + maps.get(task.getTaskName()).incrementAndGet(); + } + } + + Assert.assertEquals(3, maps.size()); + for(AtomicInteger count:maps.values()) { + log.info("Counter: {}", count.get()); + } + for(AtomicInteger count:maps.values()) { + Assert.assertEquals(numOfPersons / maps.size(), count.get()); + } + } + + private static class AssignThread extends Thread { + + private final TaskList tasks; + private final GTACourseNode node; + private final GTAManager gtaManager; + private final List<Identity> batch; + private final CourseEnvironment courseEnv; + + private int errors; + private final CountDownLatch latch; + + public AssignThread(List<Identity> batch, TaskList tasks, GTACourseNode node, + CourseEnvironment courseEnv, GTAManager gtaManager, CountDownLatch latch) { + this.batch = new ArrayList<>(batch); + this.latch = latch; + this.tasks = tasks; + this.node = node; + this.courseEnv = courseEnv; + this.gtaManager = gtaManager; + } + + public int getErrors() { + return errors; + } + + @Override + public void run() { + try { + for(Identity participant:batch) { + AssignmentResponse response = gtaManager.assignTaskAutomatically(tasks, participant, courseEnv, node); + if(response == null || response.getTask() == null || response.getStatus() != Status.ok) { + errors++; + } + DBFactory.getInstance().commitAndCloseSession(); + log.info("Assigned: {} {}", response.getStatus(), participant); + } + } catch (Exception e) { + log.error("", e); + errors++; + } finally { + DBFactory.getInstance().commitAndCloseSession(); + latch.countDown(); + } + } + } + + private void copyTestFile(File dir, String name) { + try { + URL url = JunitTestHelper.class.getResource("file_resources/task_1_a.txt"); + File courseFile = new File(url.toURI()); + File targetFile = new File(dir, name); + FileUtils.copyFileToFile(courseFile, targetFile, false); + } catch (URISyntaxException e) { + log.error("", e); + } + } + @Test public void roundRobin() { String[] slots = new String[]{ "A", "B", "C" }; diff --git a/src/test/java/org/olat/modules/forms/manager/EvaluationFormSessionDAOTest.java b/src/test/java/org/olat/modules/forms/manager/EvaluationFormSessionDAOTest.java index 10a1f5ecfe09a44fffcb50530c54588634955566..9843df6dd3431a4677ab67d570285bf0b668bbb1 100644 --- a/src/test/java/org/olat/modules/forms/manager/EvaluationFormSessionDAOTest.java +++ b/src/test/java/org/olat/modules/forms/manager/EvaluationFormSessionDAOTest.java @@ -234,23 +234,6 @@ public class EvaluationFormSessionDAOTest extends OlatTestCase { assertThat(hasSessions).isFalse(); } - @Test - public void shouldGetCountOfSessionsForSurvey() { - EvaluationFormSurvey survey = evaTestHelper.createSurvey(); - dbInstance.commit(); - - long countOfSessions = sut.getCountOfSessions(survey); - assertThat(countOfSessions).isEqualTo(0); - - evaTestHelper.createSession(survey); - evaTestHelper.createSession(survey); - dbInstance.commit(); - - countOfSessions = sut.getCountOfSessions(survey); - assertThat(countOfSessions).isEqualTo(2); - - } - @Test public void shouldDeleteSessionsOfSurvey() { EvaluationFormSurvey survey = evaTestHelper.createSurvey();