diff --git a/Modules/BookingManager/classes/class.ilBookingManagerAppEventListener.php b/Modules/BookingManager/classes/class.ilBookingManagerAppEventListener.php index 624a5f3b53ff..de3c29c33729 100644 --- a/Modules/BookingManager/classes/class.ilBookingManagerAppEventListener.php +++ b/Modules/BookingManager/classes/class.ilBookingManagerAppEventListener.php @@ -34,13 +34,11 @@ public static function handleEvent( ): void { global $DIC; - $user_event = $DIC->bookingManager()->internal()->domain()->userEvent(); - switch ($a_component) { case "Services/User": switch ($a_event) { case "deleteUser": - $user_event->handleDeletion((int) $a_parameter["usr_id"]); + $DIC->bookingManager()->internal()->domain()->userEvent()->handleDeletion((int) $a_parameter["usr_id"]); break; } break; diff --git a/Modules/Course/classes/class.ilObjCourseGUI.php b/Modules/Course/classes/class.ilObjCourseGUI.php index 3c2d87617117..a44b2695078f 100755 --- a/Modules/Course/classes/class.ilObjCourseGUI.php +++ b/Modules/Course/classes/class.ilObjCourseGUI.php @@ -759,6 +759,7 @@ public function updateObject(): void $GLOBALS['DIC']->language()->txt('crs_tile_and_objective_view_not_supported') ); $this->editObject($form); + return; } // Additional checks: both tile and session limitation activated (not supported) diff --git a/Modules/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php b/Modules/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php index 57e260a6e333..791f5e16abb8 100644 --- a/Modules/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php +++ b/Modules/Exercise/classes/BackgroundTasks/class.ilExerciseManagementCollectFilesJob.php @@ -667,6 +667,9 @@ public function getAssignmentMembersIds(): array " WHERE ass_id = " . $ilDB->quote($this->assignment->getId(), "integer")); while ($rec = $ilDB->fetchAssoc($set)) { + if (!\ilObjUser::userExists([(int) $rec['usr_id']])) { + continue; + } $members[] = $rec['usr_id']; } diff --git a/Modules/File/classes/Info/class.ilObjFileInfoRepository.php b/Modules/File/classes/Info/class.ilObjFileInfoRepository.php index de06f3e868ed..1a6bc36763ed 100755 --- a/Modules/File/classes/Info/class.ilObjFileInfoRepository.php +++ b/Modules/File/classes/Info/class.ilObjFileInfoRepository.php @@ -16,13 +16,6 @@ * *********************************************************************/ -use ILIAS\DI\Container; -use ILIAS\Filesystem\Stream\FileStream; -use ILIAS\FileUpload\DTO\UploadResult; -use ILIAS\FileUpload\FileUpload; -use ILIAS\ResourceStorage\Manager\Manager; -use ILIAS\ResourceStorage\Revision\Revision; -use ILIAS\ResourceStorage\Policy\FileNamePolicyException; use ILIAS\Data\DataSize; use ILIAS\FileUpload\MimeType; @@ -63,15 +56,30 @@ private function initInlineSuffixes(): array return array_map('strtolower', explode(' ', $settings->get('inline_file_extensions', ''))); } - public function preloadData(array $object_ids): void + public function preloadData(array $ids, bool $are_ref_ids = false): void { - $res = $this->db->query( - "SELECT title, rid, file_id, page_count FROM file_data JOIN object_data ON object_data.obj_id = file_data.file_id WHERE rid IS NOT NULL AND " . $this->db->in( + if ($are_ref_ids) { + $query = "SELECT title, rid, file_id, page_count + FROM file_data + JOIN object_data ON object_data.obj_id = file_data.file_id + JOIN object_reference ON object_reference.obj_id = object_data.obj_id + WHERE rid IS NOT NULL AND " . $this->db->in( + 'ref_id', + $ids, + false, + 'integer' + ); + } else { + $query = "SELECT title, rid, file_id, page_count FROM file_data JOIN object_data ON object_data.obj_id = file_data.file_id WHERE rid IS NOT NULL AND " . $this->db->in( 'file_id', - $object_ids, + $ids, false, 'integer' - ) + ); + } + + $res = $this->db->query( + $query ); $rids = []; $page_counts = []; @@ -113,7 +121,12 @@ public function preloadData(array $object_ids): void public function getByObjectId(int $object_id): ilObjFileInfo { + if (isset(self::$cache[$object_id])) { + return self::$cache[$object_id]; + } + $this->preloadData([$object_id]); + return self::$cache[$object_id] ?? new ilObjFileInfo( 'Unknown', null, diff --git a/Modules/File/classes/PreProcessors/class.ilCountPDFPages.php b/Modules/File/classes/PreProcessors/class.ilCountPDFPages.php index 73b1aee099d1..c6038ef3a9ab 100644 --- a/Modules/File/classes/PreProcessors/class.ilCountPDFPages.php +++ b/Modules/File/classes/PreProcessors/class.ilCountPDFPages.php @@ -16,6 +16,7 @@ * *********************************************************************/ +use ILIAS\ResourceStorage\Services; use ILIAS\FileUpload\MimeType; use ILIAS\ResourceStorage\Identification\ResourceIdentification; @@ -27,7 +28,10 @@ */ class ilCountPDFPages { - private \ILIAS\ResourceStorage\Services $irss; + /** + * @readonly + */ + private Services $irss; private bool $postscript_available = false; private bool $imagick_available = false; @@ -69,11 +73,11 @@ public function extractAmountOfPagesByPath(string $path_to_pdf): ?int if ($this->imagick_available) { $pages = null; try { - $imagick = new Imagick($path_to_pdf); - $pages = $imagick->getNumberImages(); + $imagick = new Imagick(); + $imagick->pingImage($path_to_pdf); - return $pages; - } catch (Throwable $e) { + return $imagick->getNumberImages(); + } catch (Throwable) { // Imagick is not available or another error occured } } diff --git a/Modules/File/classes/class.ilObjFile.php b/Modules/File/classes/class.ilObjFile.php index bd49dba3920d..86a0dd17b84a 100755 --- a/Modules/File/classes/class.ilObjFile.php +++ b/Modules/File/classes/class.ilObjFile.php @@ -89,11 +89,11 @@ public function __construct(int $a_id = 0, bool $a_call_by_reference = true) protected function initFileInfo(int $id, bool $is_ref_id): void { - $repository = new ilObjFileInfoRepository(true); + $repository = new ilObjFileInfoRepository(); if ($is_ref_id) { $this->file_info = $repository->getByRefId($id); } else { - $this->file_info = ($repository)->getByObjectId($id); + $this->file_info = $repository->getByObjectId($id); } } diff --git a/Modules/Glossary/Export/class.ilGlossaryDataSet.php b/Modules/Glossary/Export/class.ilGlossaryDataSet.php index eb2cd7f73b2d..423e42fa8902 100644 --- a/Modules/Glossary/Export/class.ilGlossaryDataSet.php +++ b/Modules/Glossary/Export/class.ilGlossaryDataSet.php @@ -280,9 +280,9 @@ public function importRecord( $newObj->setDescription($a_rec["Description"]); $newObj->setVirtualMode($a_rec["Virtual"]); $newObj->setPresentationMode($a_rec["PresMode"]); - $newObj->setSnippetLength($a_rec["SnippetLength"]); - $newObj->setActiveGlossaryMenu($a_rec["GloMenuActive"]); - $newObj->setShowTaxonomy($a_rec["ShowTax"]); + $newObj->setSnippetLength((int) ($a_rec["SnippetLength"] ?? 0)); + $newObj->setActiveGlossaryMenu((bool) ($a_rec["GloMenuActive"] ?? false)); + $newObj->setShowTaxonomy((bool) ($a_rec["ShowTax"] ?? false)); $newObj->setActiveFlashcards((bool) ($a_rec["FlashActive"] ?? false)); $newObj->setFlashcardsMode($a_rec["FlashMode"] ?? ""); if ($this->getCurrentInstallationId() > 0) { diff --git a/Modules/Glossary/Term/class.ilGlossaryTerm.php b/Modules/Glossary/Term/class.ilGlossaryTerm.php index 835c81bad10b..3d3ac0ebf1d5 100755 --- a/Modules/Glossary/Term/class.ilGlossaryTerm.php +++ b/Modules/Glossary/Term/class.ilGlossaryTerm.php @@ -69,6 +69,8 @@ public function read(): void $this->setImportId((string) $term_rec["import_id"]); $this->setLanguage((string) $term_rec["language"]); $this->setGlossaryId((int) $term_rec["glo_id"]); + $this->setShortText((string) $term_rec["short_text"]); + $this->setShortTextDirty((int) $term_rec["short_text_dirty"]); $this->page_object = new ilGlossaryDefPage($this->getId()); } @@ -232,8 +234,8 @@ public function create(bool $a_omit_page_creation = false): void $ilDB->quote($this->getImportId(), "text") . ", " . $ilDB->now() . ", " . $ilDB->now() . ", " . - $ilDB->quote($this->getShortText()) . ", " . - $ilDB->quote($this->getShortTextDirty()) . ")"); + $ilDB->quote($this->getShortText(), "text") . ", " . + $ilDB->quote($this->getShortTextDirty(), "integer") . ")"); if (!$a_omit_page_creation) { $this->page_object = new ilGlossaryDefPage(); diff --git a/Modules/Glossary/classes/class.ilObjGlossary.php b/Modules/Glossary/classes/class.ilObjGlossary.php index 2b21b95be15b..c0c6935c0a04 100755 --- a/Modules/Glossary/classes/class.ilObjGlossary.php +++ b/Modules/Glossary/classes/class.ilObjGlossary.php @@ -163,11 +163,11 @@ public function setSnippetLength(int $a_val): void $this->snippet_length = $a_val; } - public function getSnippetLength(): ?int + public function getSnippetLength(): int { return ($this->snippet_length > 0) ? $this->snippet_length - : null; + : 200; } public function setOnline(bool $a_online): void diff --git a/Modules/Poll/classes/BlockGUI/class.ilPollBlockGUI.php b/Modules/Poll/classes/BlockGUI/class.ilPollBlockGUI.php index 9a67e61c9544..251cf5713b2f 100644 --- a/Modules/Poll/classes/BlockGUI/class.ilPollBlockGUI.php +++ b/Modules/Poll/classes/BlockGUI/class.ilPollBlockGUI.php @@ -14,8 +14,7 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning * - ******************************************************************** - */ + *********************************************************************/ declare(strict_types=1); @@ -33,7 +32,6 @@ class ilPollBlockGUI extends ilBlockGUI public static string $block_type = "poll"; protected ilPollBlock $poll_block; public static bool $js_init = false; - protected bool $new_rendering = true; protected UIFactory $ui_factory; protected UIRenderer $ui_renderer; protected ilPollStateInfo $state; @@ -244,15 +242,6 @@ public function getNumberOfCommentsForRedraw(): void $this->comments->getNumberOfCommentsForRedraw(); } - public function fillDataSection(): void - { - $this->setDataSection($this->getLegacyContent()); - } - - // - // New rendering - // - protected function getLegacyContent(): string { $this->tpl = new ilTemplate( diff --git a/Modules/StudyProgramme/classes/class.ilPDStudyProgrammeSimpleListGUI.php b/Modules/StudyProgramme/classes/class.ilPDStudyProgrammeSimpleListGUI.php index 27f90dfa53bf..0ec786f63093 100644 --- a/Modules/StudyProgramme/classes/class.ilPDStudyProgrammeSimpleListGUI.php +++ b/Modules/StudyProgramme/classes/class.ilPDStudyProgrammeSimpleListGUI.php @@ -1,7 +1,5 @@ userHasReadableStudyProgrammes()); // We should not get here. - $this->tpl->setVariable("BLOCK_ROW", $this->getDataSectionContent()); - } - protected function userHasVisibleStudyProgrammes(): bool { if (count($this->users_assignments) === 0) { diff --git a/Modules/SurveyQuestionPool/Categories/class.ilCategoryWizardInputGUI.php b/Modules/SurveyQuestionPool/Categories/class.ilCategoryWizardInputGUI.php index 388a8d8f4c9b..dd2cf1c792ee 100644 --- a/Modules/SurveyQuestionPool/Categories/class.ilCategoryWizardInputGUI.php +++ b/Modules/SurveyQuestionPool/Categories/class.ilCategoryWizardInputGUI.php @@ -242,7 +242,7 @@ public function checkInput(): bool // check neutral column scale if ($neutral_scale != "") { - if (is_array($foundvalues['scale'])) { + if (isset($foundvalues['scale'])) { if (in_array($neutral_scale, $foundvalues['scale'])) { $this->setAlert($lng->txt("msg_duplicate_scale")); return false; diff --git a/Modules/Test/classes/Results/class.ilTestPassResultsTable.php b/Modules/Test/classes/Results/class.ilTestPassResultsTable.php index 36fcb94bc760..d49090bf25db 100644 --- a/Modules/Test/classes/Results/class.ilTestPassResultsTable.php +++ b/Modules/Test/classes/Results/class.ilTestPassResultsTable.php @@ -198,9 +198,6 @@ protected function getMapping(): \Closure $stats_fields[$lng->txt('tst_question_hints_requested_hint_count_header')] = (string)$question->getNumberOfRequestedHints(); $stats = $ui_factory->listing()->characteristicValue()->text($stats_fields); - $user_answer = $question->getUserAnswer(); - $best_solution = $env->getShowBestSolution() ? $question->getBestSolution() : ''; - $feedback = $ui_factory->listing()->descriptive([ $lng->txt('tst_feedback') => $question->getFeedback() @@ -219,11 +216,17 @@ protected function getMapping(): \Closure ]); } + $user_answer = $question->getUserAnswer(); + $answer_contents = [ + $ui_factory->listing()->descriptive([$lng->txt('tst_header_participant') => $user_answer]) + ]; + if ($env->getShowBestSolution()) { + $answer_contents[] = $ui_factory->listing()->descriptive([ + $lng->txt('tst_header_solution') => $question->getBestSolution() + ]); + } - $answers = $ui_factory->layout()->alignment()->horizontal()->evenlyDistributed( - $ui_factory->listing()->descriptive([$lng->txt('tst_header_participant') => $user_answer]), - $ui_factory->listing()->descriptive([$lng->txt('tst_header_solution') => $best_solution]) - ); + $answers = $ui_factory->layout()->alignment()->horizontal()->evenlyDistributed(...$answer_contents); $contents[] = $answers; $content = $ui_factory->layout()->alignment()->vertical(...$contents); diff --git a/Modules/Test/classes/class.ilObjTestGUI.php b/Modules/Test/classes/class.ilObjTestGUI.php index d38e880893da..dda3d995369a 100755 --- a/Modules/Test/classes/class.ilObjTestGUI.php +++ b/Modules/Test/classes/class.ilObjTestGUI.php @@ -1431,43 +1431,33 @@ public function importVerifiedFileObject() $questionParentObjId = $_POST["qpl"]; } + $imp = new ilImport($this->testrequest->getRefId()); + $map = $imp->getMapping(); + $map->addMapping('Modules/Test', 'tst', 'new_id', (string) $newObj->getId()); + + $fileName = ilSession::get('tst_import_subdir') . '.zip'; + $fullPath = ilSession::get('tst_import_dir') . '/' . $fileName; + if (is_file(ilSession::get("tst_import_dir") . '/' . ilSession::get("tst_import_subdir") . "/manifest.xml")) { $newObj->saveToDb(); ilSession::set('tst_import_idents', $_POST['ident'] ?? ''); ilSession::set('tst_import_qst_parent', $questionParentObjId); - $fileName = ilSession::get('tst_import_subdir') . '.zip'; - $fullPath = ilSession::get('tst_import_dir') . '/' . $fileName; - $imp = new ilImport($this->testrequest->getRefId()); - $map = $imp->getMapping(); - $map->addMapping('Modules/Test', 'tst', 'new_id', (string) $newObj->getId()); $imp->importObject($newObj, $fullPath, $fileName, 'tst', 'Modules/Test', true); } else { - $qtiParser = new ilQTIParser(ilSession::get("tst_import_qti_file"), ilQTIParser::IL_MO_PARSE_QTI, $questionParentObjId, $_POST["ident"] ?? ''); - if (!file_exists(ilSession::get("tst_import_results_file")) - && (!isset($_POST["ident"]) || !is_array($_POST["ident"]) || !count($_POST["ident"]))) { - $qtiParser->setIgnoreItemsEnabled(true); - } - $qtiParser->setTestObject($newObj); - $qtiParser->startParsing(); - $newObj->saveToDb(); - $questionPageParser = new ilQuestionPageParser($newObj, ilSession::get("tst_import_xml_file"), ilSession::get("tst_import_subdir")); - $questionPageParser->setQuestionMapping($qtiParser->getImportMapping()); - $questionPageParser->startParsing(); - - if (file_exists(ilSession::get("tst_import_results_file"))) { - $results = new ilTestResultsImportParser( - ilSession::get("tst_import_results_file"), - $newObj, - $this->db, - $this->logging_services->root() - ); - $results->setQuestionIdMapping($qtiParser->getQuestionIdMapping()); - $results->startParsing(); - } - - $newObj->update(); + $test_importer = new ilTestImporter(); + $test_importer->setImport($imp); + $test_importer->setInstallId(IL_INST_ID); + $test_importer->setImportDirectory(ilSession::get('tst_import_dir') . '/' . ilSession::get('tst_import_subdir')); + $test_importer->init(); + + $test_importer->importXmlRepresentation( + '', + '', + '', + $map, + ); } @@ -2480,7 +2470,7 @@ public function confirmedApplyDefaultsObject() */ public function applyDefaultsObject($confirmed = false) { - if(!$confirmed) { + if (!$confirmed) { if (!isset($_POST['chb_defaults']) || !is_array($_POST["chb_defaults"]) || 1 !== count($_POST["chb_defaults"])) { $this->tpl->setOnScreenMessage('info', $this->lng->txt("tst_defaults_apply_select_one")); @@ -2498,7 +2488,7 @@ public function applyDefaultsObject($confirmed = false) return; } - if(!$confirmed) { + if (!$confirmed) { $defaults = $this->object->getTestDefaults($_POST["chb_defaults"][0]); } else { $defaults = $this->object->getTestDefaults($_POST["confirmed_defaults_id"][0]); diff --git a/Modules/Test/classes/class.ilTestImporter.php b/Modules/Test/classes/class.ilTestImporter.php index c2454742df2f..0f96d54cef9b 100644 --- a/Modules/Test/classes/class.ilTestImporter.php +++ b/Modules/Test/classes/class.ilTestImporter.php @@ -106,35 +106,12 @@ public function importXmlRepresentation(string $a_entity, string $a_id, string $ $questionPageParser->setQuestionMapping($qtiParser->getImportMapping()); $questionPageParser->startParsing(); - foreach ($qtiParser->getQuestionIdMapping() as $oldQuestionId => $newQuestionId) { - $a_mapping->addMapping( - "Services/Taxonomy", - "tax_item", - "tst:quest:$oldQuestionId", - (string) $newQuestionId - ); - - $a_mapping->addMapping( - "Services/Taxonomy", - "tax_item_obj_id", - "tst:quest:$oldQuestionId", - (string) $new_obj->getId() - ); - - $a_mapping->addMapping( - "Modules/Test", - "quest", - (string) $oldQuestionId, - (string) $newQuestionId - ); - } + $a_mapping = $this->addTexonomyAndQuestionsMapping($qtiParser->getQuestionIdMapping(), $new_obj->getId(), $a_mapping); if ($new_obj->isRandomTest()) { - $new_obj->questions = []; $this->importRandomQuestionSetConfig($new_obj, $xml_file, $a_mapping); } - $results_file_path = ilSession::get("tst_import_results_file"); // import test results if ($results_file_path !== null && file_exists($results_file_path)) { @@ -154,6 +131,34 @@ public function importXmlRepresentation(string $a_entity, string $a_id, string $ $a_mapping->addMapping("Modules/Test", "tst", (string) $a_id, (string) $new_obj->getId()); } + public function addTexonomyAndQuestionsMapping(array $question_id_mapping, int $new_obj_id, ilImportMapping $mapping): ilImportMapping + { + foreach ($question_id_mapping as $oldQuestionId => $newQuestionId) { + $mapping->addMapping( + "Services/Taxonomy", + "tax_item", + "tst:quest:$oldQuestionId", + (string) $newQuestionId + ); + + $mapping->addMapping( + "Services/Taxonomy", + "tax_item_obj_id", + "tst:quest:$oldQuestionId", + (string) $new_obj_id + ); + + $mapping->addMapping( + "Modules/Test", + "quest", + (string) $oldQuestionId, + (string) $newQuestionId + ); + } + + return $mapping; + } + /** * Final processing * @param ilImportMapping $a_mapping @@ -300,8 +305,9 @@ private function getImportPackageName(): string return $name; } - protected function importRandomQuestionSetConfig(ilObjTest $test_obj, $xmlFile, $a_mapping) + public function importRandomQuestionSetConfig(ilObjTest $test_obj, $xmlFile, $a_mapping) { + $test_obj->questions = []; $parser = new ilObjTestXMLParser($xmlFile); $parser->setTestOBJ($test_obj); $parser->setImportMapping($a_mapping); diff --git a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php index c9a61fb8f445..b545c0088127 100755 --- a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php +++ b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php @@ -1268,7 +1268,10 @@ protected function showSideList($current_sequence_element): void $status = ILIAS\UI\Component\Listing\Workflow\Step::NOT_STARTED; - if ($row['worked_through'] || $row['isAnswered']) { + if ( + ($row['worked_through'] || $row['isAnswered']) + && $row['has_authorized_answer'] + ) { $status = ILIAS\UI\Component\Listing\Workflow\Step::IN_PROGRESS; } diff --git a/Modules/Test/classes/class.ilTestSequence.php b/Modules/Test/classes/class.ilTestSequence.php index 53f9a75bcaa8..e89dcdb2f5ba 100644 --- a/Modules/Test/classes/class.ilTestSequence.php +++ b/Modules/Test/classes/class.ilTestSequence.php @@ -631,7 +631,9 @@ public function getSequenceSummary(bool $obligationsFilterEnabled = false): arra "postponed" => $is_postponed, "sequence" => $sequence, "obligatory" => ilObjTest::isQuestionObligatory($question->getId()), - 'isAnswered' => $question->isAnswered($this->active_id, $this->pass) + 'isAnswered' => $question->isAnswered($this->active_id, $this->pass), + 'has_authorized_answer' => $question->authorizedSolutionExists($this->active_id, $this->pass) + ]; if (!$obligationsFilterEnabled || $row['obligatory']) { diff --git a/Modules/Test/classes/class.ilTestService.php b/Modules/Test/classes/class.ilTestService.php index 7963ffb68999..b140b681d254 100755 --- a/Modules/Test/classes/class.ilTestService.php +++ b/Modules/Test/classes/class.ilTestService.php @@ -261,7 +261,8 @@ public function getQuestionSummaryData(ilTestSequenceSummaryProvider $testSequen 'marked' => $marked, 'sequence' => $value["sequence"], 'obligatory' => $value['obligatory'], - 'isAnswered' => $value['isAnswered'] + 'isAnswered' => $value['isAnswered'], + 'has_authorized_answer' => $value['has_authorized_answer'], ); $firstQuestion = false; diff --git a/Modules/TestQuestionPool/classes/class.assKprimChoice.php b/Modules/TestQuestionPool/classes/class.assKprimChoice.php index 56131f944161..bf614c49af9e 100644 --- a/Modules/TestQuestionPool/classes/class.assKprimChoice.php +++ b/Modules/TestQuestionPool/classes/class.assKprimChoice.php @@ -246,8 +246,13 @@ public function loadFromDb($questionId): void $this->setOptionLabel($data['opt_label']); } - $this->setCustomTrueOptionLabel($data['custom_true']); - $this->setCustomFalseOptionLabel($data['custom_false']); + if ($data['custom_true'] !== null) { + $this->setCustomTrueOptionLabel($data['custom_true']); + } + + if ($data['custom_false'] !== null) { + $this->setCustomFalseOptionLabel($data['custom_false']); + } if ($data['score_partsol'] !== null) { $this->setScorePartialSolutionEnabled((bool) $data['score_partsol']); diff --git a/Modules/TestQuestionPool/classes/class.assKprimChoiceGUI.php b/Modules/TestQuestionPool/classes/class.assKprimChoiceGUI.php index c6391f45d415..5d1fdacd6360 100644 --- a/Modules/TestQuestionPool/classes/class.assKprimChoiceGUI.php +++ b/Modules/TestQuestionPool/classes/class.assKprimChoiceGUI.php @@ -249,8 +249,6 @@ public function writeQuestionSpecificPostData(ilPropertyFormGUI $form): void if (!$this->object->getSelfAssessmentEditingMode()) { $this->object->setAnswerType($form->getItemByPostVar('answer_type')->getValue()); - } else { - $this->object->setAnswerType(assKprimChoice::ANSWER_TYPE_MULTI_LINE); } if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($old_answer_type)) { @@ -283,20 +281,15 @@ public function writeQuestionSpecificPostData(ilPropertyFormGUI $form): void */ public function populateAnswerSpecificFormPart(ilPropertyFormGUI $form): ilPropertyFormGUI { - $kprimAnswers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers'); - $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info')); - $kprimAnswers->setSize(64); - $kprimAnswers->setMaxLength(1000); - $kprimAnswers->setRequired(true); - $kprimAnswers->setAllowMove(true); - $kprimAnswers->setQuestionObject($this->object); - if (!$this->object->getSelfAssessmentEditingMode()) { - $kprimAnswers->setSingleline($this->object->isSingleLineAnswerType($this->object->getAnswerType())); - } else { - $kprimAnswers->setSingleline(false); - } - $kprimAnswers->setValues($this->object->getAnswers()); - $form->addItem($kprimAnswers); + $answers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers'); + $answers->setInfo($this->lng->txt('kprim_answers_info')); + $answers->setSize(64); + $answers->setRequired(true); + $answers->setAllowMove(true); + $answers->setQuestionObject($this->object); + $answers->setSingleline($this->object->isSingleLineAnswerType($this->object->getAnswerType())); + $answers->setValues($this->object->getAnswers()); + $form->addItem($answers); return $form; } diff --git a/Modules/TestQuestionPool/classes/class.assMultipleChoice.php b/Modules/TestQuestionPool/classes/class.assMultipleChoice.php index 222495315c82..25abcb011cda 100755 --- a/Modules/TestQuestionPool/classes/class.assMultipleChoice.php +++ b/Modules/TestQuestionPool/classes/class.assMultipleChoice.php @@ -195,7 +195,7 @@ public function loadFromDb($question_id): void if ($data['thumb_size'] !== null && $data['thumb_size'] >= self::MINIMUM_THUMB_SIZE) { $this->setThumbSize($data['thumb_size']); } - $this->isSingleline = ($data['allow_images']) ? false : true; + $this->isSingleline = $data['allow_images'] === null || $data['allow_images'] === '0'; $this->lastChange = $data['tstamp']; $this->setSelectionLimit((int) $data['selection_limit'] > 0 ? (int) $data['selection_limit'] : null); $this->feedback_setting = $data['feedback_setting']; @@ -1394,7 +1394,7 @@ protected function buildTestPresentationConfig(): ilTestQuestionConfig return $config; } - public function isSingleline() + public function isSingleline(): bool { return (bool) $this->isSingleline; } diff --git a/Modules/TestQuestionPool/classes/class.assMultipleChoiceGUI.php b/Modules/TestQuestionPool/classes/class.assMultipleChoiceGUI.php index d37d01529b5e..b5274d84603d 100755 --- a/Modules/TestQuestionPool/classes/class.assMultipleChoiceGUI.php +++ b/Modules/TestQuestionPool/classes/class.assMultipleChoiceGUI.php @@ -89,6 +89,10 @@ protected function writePostData(bool $always = false): int */ protected function getEditAnswersSingleLine($checkonly = false): bool { + if ($this->object->getSelfAssessmentEditingMode()) { + return $this->object->isSingleline(); + } + if ($checkonly) { $types = $_POST['types'] ?? '0'; return $types === '0' ? true : false; @@ -824,7 +828,6 @@ public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $i if ($this->object->getSelfAssessmentEditingMode()) { $choices->setSize(40); } - $choices->setMaxLength(800); if ($this->object->getAnswerCount() == 0) { $this->object->addAnswer("", 0, 0, 0); } diff --git a/Modules/TestQuestionPool/classes/class.assSingleChoice.php b/Modules/TestQuestionPool/classes/class.assSingleChoice.php index de3c5d296328..eab3a2aedae2 100755 --- a/Modules/TestQuestionPool/classes/class.assSingleChoice.php +++ b/Modules/TestQuestionPool/classes/class.assSingleChoice.php @@ -193,7 +193,7 @@ public function loadFromDb($question_id): void if ($data['thumb_size'] !== null && $data['thumb_size'] >= self::MINIMUM_THUMB_SIZE) { $this->setThumbSize($data['thumb_size']); } - $this->isSingleline = ($data['allow_images']) ? false : true; + $this->isSingleline = $data['allow_images'] === null || $data['allow_images'] === '0'; $this->lastChange = $data['tstamp']; $this->feedback_setting = $data['feedback_setting']; diff --git a/Modules/TestQuestionPool/classes/class.assSingleChoiceGUI.php b/Modules/TestQuestionPool/classes/class.assSingleChoiceGUI.php index a3b7ecd427f2..894faa4b17c5 100755 --- a/Modules/TestQuestionPool/classes/class.assSingleChoiceGUI.php +++ b/Modules/TestQuestionPool/classes/class.assSingleChoiceGUI.php @@ -84,6 +84,10 @@ protected function writePostData(bool $always = false): int */ protected function getEditAnswersSingleLine($checkonly = false): bool { + if ($this->object->getSelfAssessmentEditingMode()) { + return $this->object->isSingleline(); + } + if ($checkonly) { $types = $_POST['types'] ?? '0'; return $types === '0' ? true : false; @@ -704,7 +708,6 @@ public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $i if ($this->object->getSelfAssessmentEditingMode()) { $choices->setSize(40); } - $choices->setMaxLength(800); if ($this->object->getAnswerCount() == 0) { $this->object->addAnswer("", 0, 0); } @@ -804,7 +807,7 @@ private function populateInlineFeedback($template, $answer_id, $user_solution): break; case 2: - if (strcmp((string)$user_solution, $answer_id) == 0) { + if (strcmp((string) $user_solution, $answer_id) == 0) { $feedbackOutputRequired = true; } break; diff --git a/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php b/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php index 78e1728f110f..a1aa0205d3e6 100755 --- a/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php +++ b/Modules/TestQuestionPool/classes/class.assTextQuestionGUI.php @@ -711,6 +711,7 @@ public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form): ilProp //$allKeyword->setQuestionObject($this->object); //$allKeyword->setSingleline(TRUE); $allKeyword->setValues(self::buildAnswerTextOnlyArray($this->object->getAnswers())); + $allKeyword->setMaxLength($anyKeyword->getMaxLength()); $scoringOptionAllKeyword->addSubItem($allKeyword); $allKeywordPoints = new ilNumberInputGUI($this->lng->txt("points"), "all_keyword_points"); $allKeywordPoints->allowDecimals(true); @@ -727,6 +728,7 @@ public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form): ilProp //$oneKeyword->setQuestionObject($this->object); //$oneKeyword->setSingleline(TRUE); $oneKeyword->setValues(self::buildAnswerTextOnlyArray($this->object->getAnswers())); + $oneKeyword->setMaxLength($anyKeyword->getMaxLength()); $scoringOptionOneKeyword->addSubItem($oneKeyword); $oneKeywordPoints = new ilNumberInputGUI($this->lng->txt("points"), "one_keyword_points"); $oneKeywordPoints->allowDecimals(true); diff --git a/Modules/TestQuestionPool/classes/class.ilAssQuestionList.php b/Modules/TestQuestionPool/classes/class.ilAssQuestionList.php index ff4a6124ad6e..7ff1317e4fba 100644 --- a/Modules/TestQuestionPool/classes/class.ilAssQuestionList.php +++ b/Modules/TestQuestionPool/classes/class.ilAssQuestionList.php @@ -119,7 +119,7 @@ public function setParentObjIdsFilter($parentObjIdsFilter): void public function setQuestionInstanceTypeFilter($questionInstanceTypeFilter): void { - $this->questionInstanceTypeFilter = (string)$questionInstanceTypeFilter; + $this->questionInstanceTypeFilter = (string) $questionInstanceTypeFilter; } public function getQuestionInstanceTypeFilter() @@ -293,7 +293,7 @@ private function getFieldFilterExpressions(): array private function getTaxonomyFilterExpressions(): array { $expressions = []; - if($this->taxFiltersExcludeAnyObjectsWithTaxonomies) { + if ($this->taxFiltersExcludeAnyObjectsWithTaxonomies) { $expressions[] = 'question_id NOT IN (SELECT DISTINCT item_id FROM tax_node_assignment)'; return $expressions; } @@ -582,8 +582,8 @@ public function load(): void $row['author'] = $tags_trafo->transform($row['author']); $row['taxonomies'] = $this->loadTaxonomyAssignmentData($row['obj_fi'], $row['question_id']); $row['ttype'] = $this->lng->txt($row['type_tag']); - $row['feedback'] = $this->hasGenericFeedback((int)$row['question_id']); - $row['hints'] = $this->hasHints((int)$row['question_id']); + $row['feedback'] = $this->hasFeedback((int) $row['question_id']); + $row['hints'] = $this->hasHints((int) $row['question_id']); $row['comments'] = $this->getNumberOfCommentsForQuestion($row['question_id']); if ( @@ -615,14 +615,32 @@ public function setCommentFilter(int $commented = null) $this->filter_comments = $commented; } - protected function hasGenericFeedback(int $question_id): bool + protected function hasFeedback(int $question_id): bool { + $pagetypes = [ + \ilAssQuestionFeedback::PAGE_OBJECT_TYPE_GENERIC_FEEDBACK, + \ilAssQuestionFeedback::PAGE_OBJECT_TYPE_SPECIFIC_FEEDBACK, + ]; $res = $this->db->queryF( - "SELECT * FROM qpl_fb_generic WHERE question_fi = %s", - ['integer'], - [$question_id] + "SELECT feedback, feedback_id FROM qpl_fb_generic + WHERE question_fi = %s + UNION ALL + SELECT feedback, feedback_id FROM qpl_fb_specific + WHERE question_fi = %s", + ['integer', 'integer', ], + [$question_id, $question_id] ); - return $this->db->numRows($res) > 0; + while ($row = $this->db->fetchAssoc($res)) { + if (trim((string) $row['feedback']) !== '') { + return true; + } + foreach ($pagetypes as $pagetype) { + if (\ilPageUtil::_existsAndNotEmpty($pagetype, $row['feedback_id'])) { + return true; + } + } + } + return false; } protected function hasHints(int $question_id): bool diff --git a/Modules/TestQuestionPool/classes/class.ilEssayKeywordWizardInputGUI.php b/Modules/TestQuestionPool/classes/class.ilEssayKeywordWizardInputGUI.php index fec2ce8cb74e..c5773147f086 100644 --- a/Modules/TestQuestionPool/classes/class.ilEssayKeywordWizardInputGUI.php +++ b/Modules/TestQuestionPool/classes/class.ilEssayKeywordWizardInputGUI.php @@ -68,6 +68,11 @@ public function checkInput(): bool $this->setAlert($lng->txt("msg_input_is_required")); return false; } + + if (mb_strlen($answervalue) > $this->getMaxLength()) { + $this->setAlert($lng->txt("msg_input_char_limit_max")); + return false; + } } } // check points diff --git a/Modules/TestQuestionPool/classes/class.ilKprimChoiceWizardInputGUI.php b/Modules/TestQuestionPool/classes/class.ilKprimChoiceWizardInputGUI.php index 0f95f7b2ed8e..ba7f98e47702 100644 --- a/Modules/TestQuestionPool/classes/class.ilKprimChoiceWizardInputGUI.php +++ b/Modules/TestQuestionPool/classes/class.ilKprimChoiceWizardInputGUI.php @@ -132,6 +132,11 @@ public function checkInput(): bool $this->setAlert($lng->txt("msg_input_is_required")); return false; } + + if (mb_strlen($answervalue) > $this->getMaxLength()) { + $this->setAlert($lng->txt("msg_input_char_limit_max")); + return false; + } } } @@ -223,6 +228,7 @@ public function insert(ilTemplate $a_tpl): void $tpl->setVariable("MULTILINE_ID", $this->getPostVar() . "[answer][{$value->getPosition()}]"); $tpl->setVariable("MULTILINE_ROW_NUMBER", $value->getPosition()); $tpl->setVariable("MULTILINE_POST_VAR", $this->getPostVar()); + $tpl->setVariable("MAXLENGTH", $this->getMaxLength()); if ($this->getDisabled()) { $tpl->setVariable("DISABLED_MULTILINE", " disabled=\"disabled\""); } diff --git a/Modules/TestQuestionPool/classes/class.ilMultipleChoiceWizardInputGUI.php b/Modules/TestQuestionPool/classes/class.ilMultipleChoiceWizardInputGUI.php index 44aed6348604..6f1690511f0c 100644 --- a/Modules/TestQuestionPool/classes/class.ilMultipleChoiceWizardInputGUI.php +++ b/Modules/TestQuestionPool/classes/class.ilMultipleChoiceWizardInputGUI.php @@ -75,6 +75,11 @@ public function checkInput(): bool $this->setAlert($lng->txt("msg_input_is_required")); return false; } + + if (mb_strlen($answervalue) > $this->getMaxLength()) { + $this->setAlert($lng->txt("msg_input_char_limit_max")); + return false; + } } } // check points @@ -303,6 +308,7 @@ public function insert(ilTemplate $a_tpl): void $tpl->setVariable("MULTILINE_ID", $this->getPostVar() . "[answer][$i]"); $tpl->setVariable("MULTILINE_ROW_NUMBER", $i); $tpl->setVariable("MULTILINE_POST_VAR", $this->getPostVar()); + $tpl->setVariable("MAXLENGTH", $this->getMaxLength()); if ($this->getDisabled()) { $tpl->setVariable("DISABLED_MULTILINE", " disabled=\"disabled\""); } diff --git a/Modules/TestQuestionPool/classes/class.ilSingleChoiceWizardInputGUI.php b/Modules/TestQuestionPool/classes/class.ilSingleChoiceWizardInputGUI.php index bb2f5b45cbf5..f71b4b7a577c 100755 --- a/Modules/TestQuestionPool/classes/class.ilSingleChoiceWizardInputGUI.php +++ b/Modules/TestQuestionPool/classes/class.ilSingleChoiceWizardInputGUI.php @@ -52,6 +52,7 @@ public function __construct($a_title = '', $a_postvar = '') parent::__construct($a_title, $a_postvar); $this->setSuffixes(['jpg', 'jpeg', 'png', 'gif']); $this->setSize('25'); + $this->setMaxLength(1000); $this->validationRegexp = ''; global $DIC; @@ -247,6 +248,11 @@ public function checkInput(): bool $this->setAlert($lng->txt("msg_input_is_required")); return false; } + + if (mb_strlen($answervalue) > $this->getMaxLength()) { + $this->setAlert($lng->txt("msg_input_char_limit_max")); + return false; + } } } // check points @@ -457,6 +463,7 @@ public function insert(ilTemplate $a_tpl): void $tpl->setVariable("MULTILINE_ID", $this->getPostVar() . "[answer][$i]"); $tpl->setVariable("MULTILINE_ROW_NUMBER", $i); $tpl->setVariable("MULTILINE_POST_VAR", $this->getPostVar()); + $tpl->setVariable("MAXLENGTH", $this->getMaxLength()); if ($this->getDisabled()) { $tpl->setVariable("DISABLED_MULTILINE", " disabled=\"disabled\""); } diff --git a/Modules/TestQuestionPool/classes/import/qti12/class.assClozeTestImport.php b/Modules/TestQuestionPool/classes/import/qti12/class.assClozeTestImport.php index ccbd26a8ebc3..27344daa45b4 100644 --- a/Modules/TestQuestionPool/classes/import/qti12/class.assClozeTestImport.php +++ b/Modules/TestQuestionPool/classes/import/qti12/class.assClozeTestImport.php @@ -16,29 +16,29 @@ *********************************************************************/ /** -* Class for cloze question imports -* -* assClozeTestImport is a class for cloze question imports -* -* @author Helmut Schottmüller -* @version $Id$ -* @ingroup ModulesTestQuestionPool -*/ + * Class for cloze question imports + * + * assClozeTestImport is a class for cloze question imports + * + * @author Helmut Schottmüller + * @version $Id$ + * @ingroup ModulesTestQuestionPool + */ class assClozeTestImport extends assQuestionImport { /** - * Creates a question from a QTI file - * - * Receives parameters from a QTI parser and creates a valid ILIAS question object - * - * @param ilQTIItem $item The QTI item object - * @param integer $questionpool_id The id of the parent questionpool - * @param integer $tst_id The id of the parent test if the question is part of a test - * @param object $tst_object A reference to the parent test object - * @param integer $question_counter A reference to a question counter to count the questions of an imported question pool - * @param array $import_mapping An array containing references to included ILIAS objects - * @access public - */ + * Creates a question from a QTI file + * + * Receives parameters from a QTI parser and creates a valid ILIAS question object + * + * @param ilQTIItem $item The QTI item object + * @param integer $questionpool_id The id of the parent questionpool + * @param integer $tst_id The id of the parent test if the question is part of a test + * @param object $tst_object A reference to the parent test object + * @param integer $question_counter A reference to a question counter to count the questions of an imported question pool + * @param array $import_mapping An array containing references to included ILIAS objects + * @access public + */ public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$question_counter, $import_mapping): array { global $DIC; @@ -64,7 +64,12 @@ public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$ques $presentation->material[$entry["index"]] ); - array_push($clozetext_array, $material_string); + if ($questiontext === ' ') { + //needs to be checked here to suport imports from >= 5.4 < 9.0 + $questiontext = $material_string; + } else { + array_push($clozetext_array, $material_string); + } break; case "response": @@ -94,9 +99,9 @@ public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$ques array_push( $gaps, ["ident" => $response->getIdent(), - "type" => CLOZE_TEXT, - "answers" => [], - 'gap_size' => $response->getRenderType()->getMaxchars() + "type" => CLOZE_TEXT, + "answers" => [], + 'gap_size' => $response->getRenderType()->getMaxchars() ] ); break; @@ -246,7 +251,7 @@ public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$ques $this->object->setIdenticalScoring($item->getMetadataEntry("identicalScoring")); $this->object->setFeedbackMode( strlen($item->getMetadataEntry("feedback_mode")) ? - $item->getMetadataEntry("feedback_mode") : ilAssClozeTestFeedback::FB_MODE_GAP_QUESTION + $item->getMetadataEntry("feedback_mode") : ilAssClozeTestFeedback::FB_MODE_GAP_QUESTION ); $combinations = json_decode(base64_decode($item->getMetadataEntry("combinations"))); if (strlen($textgap_rating) == 0) { @@ -316,7 +321,8 @@ public function fromXML(&$item, $questionpool_id, &$tst_id, &$tst_object, &$ques } else { $importfile = $this->getQplImportArchivDirectory() . '/' . $mob["uri"]; } - global $DIC; /* @var ILIAS\DI\Container $DIC */ + global $DIC; + /* @var ILIAS\DI\Container $DIC */ $DIC['ilLog']->write(__METHOD__ . ': import mob from dir: ' . $importfile); $media_object = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false); diff --git a/Modules/TestQuestionPool/templates/default/tpl.prop_kprimchoicewizardinput.html b/Modules/TestQuestionPool/templates/default/tpl.prop_kprimchoicewizardinput.html index e4b00c445964..832012d67bea 100644 --- a/Modules/TestQuestionPool/templates/default/tpl.prop_kprimchoicewizardinput.html +++ b/Modules/TestQuestionPool/templates/default/tpl.prop_kprimchoicewizardinput.html @@ -44,7 +44,7 @@ - + @@ -72,4 +72,4 @@ - \ No newline at end of file + diff --git a/Modules/TestQuestionPool/templates/default/tpl.prop_multiplechoicewizardinput.html b/Modules/TestQuestionPool/templates/default/tpl.prop_multiplechoicewizardinput.html index 92043d334f18..207260b99fa5 100644 --- a/Modules/TestQuestionPool/templates/default/tpl.prop_multiplechoicewizardinput.html +++ b/Modules/TestQuestionPool/templates/default/tpl.prop_multiplechoicewizardinput.html @@ -27,7 +27,7 @@ value="{PROPERTY_VALUE}" {DISABLED_SINGLELINE}/> - + @@ -79,4 +79,4 @@
{TXT_MAX_SIZE} {TXT_ALLOWED_SUFFIXES}
- \ No newline at end of file + diff --git a/Modules/TestQuestionPool/templates/default/tpl.prop_singlechoicewizardinput.html b/Modules/TestQuestionPool/templates/default/tpl.prop_singlechoicewizardinput.html index 6db8f9144c8b..3e8e267293b6 100644 --- a/Modules/TestQuestionPool/templates/default/tpl.prop_singlechoicewizardinput.html +++ b/Modules/TestQuestionPool/templates/default/tpl.prop_singlechoicewizardinput.html @@ -22,7 +22,7 @@ value="{PROPERTY_VALUE}" {DISABLED_SINGLELINE}/> - + diff --git a/Modules/Wiki/classes/class.ilWikiFunctionsBlockGUI.php b/Modules/Wiki/classes/class.ilWikiFunctionsBlockGUI.php index 1351cd274687..9b9718344481 100644 --- a/Modules/Wiki/classes/class.ilWikiFunctionsBlockGUI.php +++ b/Modules/Wiki/classes/class.ilWikiFunctionsBlockGUI.php @@ -102,19 +102,6 @@ public function getPageObject(): ilWikiPage { return $this->pageob; } - - public function fillDataSection(): void - { - $this->setDataSection($this->getLegacyContent()); - } - - // - // New rendering - // - - protected bool $new_rendering = true; - - protected function getLegacyContent(): string { $ilCtrl = $this->ctrl; diff --git a/Modules/Wiki/classes/class.ilWikiImportantPagesBlockGUI.php b/Modules/Wiki/classes/class.ilWikiImportantPagesBlockGUI.php index 7abf7b278ea3..c55984b1098e 100644 --- a/Modules/Wiki/classes/class.ilWikiImportantPagesBlockGUI.php +++ b/Modules/Wiki/classes/class.ilWikiImportantPagesBlockGUI.php @@ -106,19 +106,6 @@ public function getHTML(bool $a_export = false): string return parent::getHTML(); } - - public function fillDataSection(): void - { - $this->setDataSection($this->getLegacyContent()); - } - - // - // New rendering - // - - protected bool $new_rendering = true; - - protected function getLegacyContent(): string { $ilCtrl = $this->ctrl; diff --git a/Services/ADT/classes/Types/ExternalLink/class.ilADTExternalLinkSearchBridgeSingle.php b/Services/ADT/classes/Types/ExternalLink/class.ilADTExternalLinkSearchBridgeSingle.php index aeeeb6a7f3f2..acb367430afa 100644 --- a/Services/ADT/classes/Types/ExternalLink/class.ilADTExternalLinkSearchBridgeSingle.php +++ b/Services/ADT/classes/Types/ExternalLink/class.ilADTExternalLinkSearchBridgeSingle.php @@ -1,7 +1,5 @@ @@ -146,9 +146,12 @@ public function getSQLCondition(string $a_element_id, int $mode = self::SQL_LIKE public function isInCondition(ilADT $a_adt): bool { if ($this->getADT()->getCopyOfDefinition()->isComparableTo($a_adt)) { + $search_term = strtolower(trim((string) $this->getADT()->getUrl())); + $title = strtolower(trim((string) $a_adt->getTitle())); + $url = strtolower(trim((string) $a_adt->getUrl())); return - strcasecmp(trim($this->getADT()->getUrl()), trim((string) $a_adt->getUrl())) === 0 || - strcasecmp(trim($this->getADT()->getUrl()), trim((string) $a_adt->getTitle())) === 0; + str_contains($title, $search_term) || + str_contains($url, $search_term); } return false; } diff --git a/Services/ADT/classes/Types/InternalLink/class.ilADTInternalLinkSearchBridgeSingle.php b/Services/ADT/classes/Types/InternalLink/class.ilADTInternalLinkSearchBridgeSingle.php index f18ee43e9af9..0a13403f86be 100644 --- a/Services/ADT/classes/Types/InternalLink/class.ilADTInternalLinkSearchBridgeSingle.php +++ b/Services/ADT/classes/Types/InternalLink/class.ilADTInternalLinkSearchBridgeSingle.php @@ -1,7 +1,5 @@ @@ -132,8 +132,11 @@ public function isInCondition(ilADT $a_adt): bool { if ($this->getADT()->getCopyOfDefinition()->isComparableTo($a_adt)) { $ref_id = $a_adt->getTargetRefId(); - $title = ilObject::_lookupTitle((int) ilObject::_lookupObjId((int) $ref_id)); - return strcasecmp($title, $this->getTitleQuery()) === 0; + $title = strtolower(trim( + ilObject::_lookupTitle((int) ilObject::_lookupObjId((int) $ref_id)) + )); + $query = strtolower(trim($this->getTitleQuery())); + return str_contains($title, $query); } return false; } diff --git a/Services/ADT/classes/Types/LocalizedText/class.ilADTLocalizedTextSearchBridgeSingle.php b/Services/ADT/classes/Types/LocalizedText/class.ilADTLocalizedTextSearchBridgeSingle.php index f9dc7c098229..d72f8d76b955 100644 --- a/Services/ADT/classes/Types/LocalizedText/class.ilADTLocalizedTextSearchBridgeSingle.php +++ b/Services/ADT/classes/Types/LocalizedText/class.ilADTLocalizedTextSearchBridgeSingle.php @@ -123,8 +123,10 @@ public function isInCondition(ilADT $a_adt): bool $a_adt->getTranslations() : [$a_adt->getTextForLanguage($a_adt->getCopyOfDefinition()->getDefaultLanguage())]; - foreach ($relevant_translation as $txt) { - if (str_contains(strtolower($txt), strtolower($this->getADT()->getText()))) { + foreach ($relevant_translation as $text) { + $search_term = strtolower(trim((string) $this->getADT()->getText())); + $text = strtolower(trim((string) $text)); + if (str_contains($text, $search_term)) { return true; } } diff --git a/Services/ADT/classes/Types/Text/class.ilADTTextSearchBridgeSingle.php b/Services/ADT/classes/Types/Text/class.ilADTTextSearchBridgeSingle.php index 16ee84cd21e3..1b177e6bc92b 100644 --- a/Services/ADT/classes/Types/Text/class.ilADTTextSearchBridgeSingle.php +++ b/Services/ADT/classes/Types/Text/class.ilADTTextSearchBridgeSingle.php @@ -139,9 +139,9 @@ public function getSQLCondition(string $a_element_id, int $mode = self::SQL_LIKE public function isInCondition(ilADT $a_adt): bool { if ($this->getADT()->getCopyOfDefinition()->isComparableTo($a_adt)) { - if (str_contains(strtolower($a_adt->getText()), strtolower($this->getADT()->getText()))) { - return true; - } + $search_term = strtolower(trim((string) $this->getADT()->getText())); + $text = strtolower(trim((string) $a_adt->getText())); + return str_contains($text, $search_term); } return false; } diff --git a/Services/Authentication/classes/Frontend/class.ilAuthFrontend.php b/Services/Authentication/classes/Frontend/class.ilAuthFrontend.php index 3f58bbf62401..ce63cab9ffea 100644 --- a/Services/Authentication/classes/Frontend/class.ilAuthFrontend.php +++ b/Services/Authentication/classes/Frontend/class.ilAuthFrontend.php @@ -446,22 +446,40 @@ protected function handleAuthenticationFail(): bool { $this->logger->debug('Authentication failed for all authentication methods.'); - $user_id = ilObjUser::_lookupId($this->getCredentials()->getUsername()); - if (is_int($user_id) && $user_id !== ANONYMOUS_USER_ID) { - ilObjUser::_incrementLoginAttempts($user_id); - $login_attempts = ilObjUser::_getLoginAttempts($user_id); + $this->handleLoginAttempts(); - $this->logger->notice('Increased login attempts for user: ' . $this->getCredentials()->getUsername()); + return false; + } - $security = ilSecuritySettings::_getInstance(); - $max_attempts = $security->getLoginMaxAttempts(); + protected function handleLoginAttempts(): void + { + $security = ilSecuritySettings::_getInstance(); + $max_attempts = $security->getLoginMaxAttempts(); + if ($max_attempts < 1) { + return; + } - if ($max_attempts && $login_attempts >= $max_attempts) { - $this->getStatus()->setReason('auth_err_login_attempts_deactivation'); - $this->logger->warning('User account set to inactive due to exceeded login attempts.'); - ilObjUser::_setUserInactive($user_id); - } + $usr_id = ilObjUser::_lookupId($this->getCredentials()->getUsername()); + if ($usr_id === ANONYMOUS_USER_ID || !is_int($usr_id)) { + return; + } + + $num_login_attempts = ilObjUser::_getLoginAttempts($usr_id); + + if ($num_login_attempts <= $max_attempts) { + ilObjUser::_incrementLoginAttempts($usr_id); + } + + if ($num_login_attempts >= $max_attempts) { + ilObjUser::_setUserInactive($usr_id); + + $this->logger->warning( + sprintf( + 'User account %s with id %s set to inactive due to exceeded login attempts.', + $this->getCredentials()->getUsername(), + $usr_id + ) + ); } - return false; } } diff --git a/Services/Block/classes/class.ilBlockGUI.php b/Services/Block/classes/class.ilBlockGUI.php index 7016747b24f3..11aa66424856 100644 --- a/Services/Block/classes/class.ilBlockGUI.php +++ b/Services/Block/classes/class.ilBlockGUI.php @@ -378,239 +378,100 @@ public function getHTML(): string { $this->initCommands(); - // old rendering is obsolete - //if ($this->new_rendering) { - return $this->getHTMLNew(); - //} + $access = $this->access; + $panel = null; - $ilCtrl = $this->ctrl; - $lng = $this->lng; - $ilAccess = $this->access; - $ilUser = $this->user; - $objDefinition = $this->obj_def; + $ctrl = $this->ctrl; if ($this->isRepositoryObject()) { - if (!$ilAccess->checkAccess("read", "", $this->getRefId())) { + if (!$access->checkAccess("read", "", $this->getRefId())) { return ""; } } - $this->tpl = new ilTemplate("tpl.block.html", true, true, "Services/Block"); - - // $this->handleConfigStatus(); - - $this->fillDataSection(); - if ($this->getRepositoryMode() && $this->isRepositoryObject()) { - // #10993 - // @todo: fix this in new presentation somehow - if ($this->getAdminCommands()) { - $this->tpl->setCurrentBlock("block_check"); - $this->tpl->setVariable("BL_REF_ID", $this->getRefId()); - $this->tpl->parseCurrentBlock(); - } + $this->addRepoCommands(); - if ($ilAccess->checkAccess("delete", "", $this->getRefId())) { - $this->addBlockCommand( - "ilias.php?baseClass=ilRepositoryGUI&ref_id=" . $this->requested_ref_id . "&cmd=delete" . - "&item_ref_id=" . $this->getRefId(), - $lng->txt("delete") + switch ($this->getPresentation()) { + case self::PRES_SEC_LEG: + $panel = $this->factory->panel()->secondary()->legacy( + $this->specialCharsAsEntities($this->getTitle()), + $this->factory->legacy($this->getLegacyContent()) ); + break; - // see ilObjectListGUI::insertCutCommand(); - $this->addBlockCommand( - "ilias.php?baseClass=ilRepositoryGUI&ref_id=" . $this->requested_ref_id . "&cmd=cut" . - "&item_ref_id=" . $this->getRefId(), - $lng->txt("move") + case self::PRES_MAIN_LEG: + $panel = $this->factory->panel()->standard( + $this->specialCharsAsEntities($this->getTitle()), + $this->factory->legacy($this->getLegacyContent()) ); - } - - // #14595 - see ilObjectListGUI::insertCopyCommand() - if ($ilAccess->checkAccess("copy", "", $this->getRefId())) { - $parent_type = ilObject::_lookupType($this->requested_ref_id, true); - $parent_gui = "ilObj" . $objDefinition->getClassName($parent_type) . "GUI"; + break; - $ilCtrl->setParameterByClass("ilobjectcopygui", "source_id", $this->getRefId()); - $copy_cmd = $ilCtrl->getLinkTargetByClass( - array("ilrepositorygui", $parent_gui, "ilobjectcopygui"), - "initTargetSelection" + case self::PRES_SEC_LIST: + $this->handleNavigation(); + $panel = $this->factory->panel()->secondary()->listing( + $this->specialCharsAsEntities($this->getTitle()), + $this->getListItemGroups() ); + break; - // see ilObjectListGUI::insertCopyCommand(); - $this->addBlockCommand( - $copy_cmd, - $lng->txt("copy") + case self::PRES_MAIN_TILE: + case self::PRES_MAIN_LIST: + $this->handleNavigation(); + $panel = $this->factory->panel()->listing()->standard( + $this->specialCharsAsEntities($this->getTitle()), + $this->getListItemGroups() ); - } + break; } - $this->dropdown = array(); - - // commands - if (count($this->getBlockCommands()) > 0) { - foreach ($this->getBlockCommands() as $command) { - if ($command["onclick"]) { - $command["onclick"] = "ilBlockJSHandler('" . "block_" . $this->getBlockType() . "_" . $this->block_id . - "','" . $command["onclick"] . "')"; - } - $this->dropdown[] = $command; + // check for empty list panel + if (in_array($this->getPresentation(), [self::PRES_SEC_LIST, self::PRES_MAIN_LIST], true) && + ($panel->getItemGroups() === [] || (count($panel->getItemGroups()) === 1 && $panel->getItemGroups()[0]->getItems() === []))) { + if ($this->getPresentation() === self::PRES_SEC_LIST) { + $panel = $this->factory->panel()->secondary()->legacy( + $this->specialCharsAsEntities($this->getTitle()), + $this->factory->legacy($this->getNoItemFoundContent()) + ); + } else { + $panel = $this->factory->panel()->standard( + $this->specialCharsAsEntities($this->getTitle()), + $this->factory->legacy($this->getNoItemFoundContent()) + ); } } - // fill previous next - $this->fillPreviousNext(); - - // fill footer - $this->fillFooter(); - - - //$this->fillHeaderCommands(); - $this->fillHeaderTitleBlock(); - - if ($this->getPresentation() === self::PRES_MAIN_LEG) { - $this->tpl->touchBlock("hclassb"); - } else { - $this->tpl->touchBlock("hclass"); - } - - if ($ilCtrl->isAsynch()) { - // return without div wrapper - echo $this->tpl->get(); - //echo $this->tpl->getAsynch(); - } else { - // return incl. wrapping div with id - return '
getBlockType() . "_" . $this->block_id . '">' . - $this->tpl->get() . '
'; + $actions = $this->getActionsForPanel(); + if ($actions !== null) { + $panel = $panel->withActions($actions); } - return ""; - } - - public function fillHeaderTitleBlock(): void - { - $lng = $this->lng; - - - // header title - $this->tpl->setCurrentBlock("header_title"); - $this->tpl->setVariable( - "BTID", - "block_" . $this->getBlockType() . "_" . $this->block_id - ); - $this->tpl->setVariable( - "BLOCK_TITLE", - $this->getTitle() - ); - $this->tpl->setVariable( - "TXT_BLOCK", - $lng->txt("block") - ); - $this->tpl->parseCurrentBlock(); - - $this->tpl->setCurrentBlock("hitem"); - $this->tpl->parseCurrentBlock(); - } - - /** - * Call this from overwritten fillDataSection(), if standard row based data is not used. - */ - public function setDataSection(string $a_content): void - { - $this->tpl->setCurrentBlock("data_section"); - $this->tpl->setVariable("DATA", $a_content); - $this->tpl->parseCurrentBlock(); - $this->tpl->setVariable("BLOCK_ROW", ""); - } - - /** - * Standard implementation for row based data. - * Overwrite this and call setContent for other data. - */ - public function fillDataSection(): void - { - $req_nav_par = $this->request->getNavPar($this->getNavParameter()); - if ($req_nav_par != "") { - $this->nav_value = $req_nav_par; + $viewControls = $this->getViewControlsForPanel(); + if ($viewControls !== [] && + ( + $panel instanceof StandardPanel || + $panel instanceof SecondaryListingPanel || + $panel instanceof SecondaryLegacyPanel || + $panel instanceof StandardListingPanel + ) + ) { + $panel = $panel->withViewControls($viewControls); } - $this->nav_value = ($this->nav_value != "") - ? $this->nav_value - : $this->block_manager->getNavPar($this->getNavParameter()); - - $this->block_manager->setNavPar( - $this->getNavParameter(), - $this->nav_value - ); - $nav = explode(":", $this->nav_value); - if (isset($nav[2])) { - $this->setOffset((int) $nav[2]); + if ($ctrl->isAsynch()) { + $html = $this->renderer->renderAsync([$panel, ...$this->modals]); } else { - $this->setOffset(0); - } - - // data - $this->tpl->addBlockFile( - "BLOCK_ROW", - "block_row", - $this->getRowTemplateName(), - $this->getRowTemplateDir() - ); - - $data = $this->getData(); - $this->max_count = count($data); - $data = array_slice($data, $this->getOffset(), $this->getLimit()); - - $this->preloadData($data); - - foreach ($data as $record) { - $this->tpl->setCurrentBlock("block_row"); - $this->fillRowColor(); - $this->fillRow($record); - $this->tpl->setCurrentBlock("block_row"); - $this->tpl->parseCurrentBlock(); - } - } - - public function fillRow(array $a_set): void - { - foreach ($a_set as $key => $value) { - $this->tpl->setVariable("VAL_" . strtoupper($key), $value); + $html = $this->renderer->render([$panel, ...$this->modals]); } - } - - public function fillFooter(): void - { - } - - final protected function fillRowColor(string $a_placeholder = "CSS_ROW"): void - { - $this->css_row = ($this->css_row != "ilBlockRow1") - ? "ilBlockRow1" - : "ilBlockRow2"; - $this->tpl->setVariable($a_placeholder, $this->css_row); - } - - public function fillPreviousNext(): void - { - $lng = $this->lng; - // table pn numinfo - $numinfo = ""; - if ($this->getEnableNumInfo() && $this->max_count > 0) { - $start = $this->getOffset() + 1; // compute num info - $end = $this->getOffset() + $this->getLimit(); - if ($end > $this->max_count or $this->getLimit() == 0) { - $end = $this->max_count; - } - - $numinfo = "(" . $start . "-" . $end . " " . strtolower($lng->txt("of")) . " " . $this->max_count . ")"; + if ($ctrl->isAsynch()) { + $this->send($html); + } else { + // return incl. wrapping div with id + $html = '
' . + $html . '
'; } - $this->setPreviousNextLinks(); - $this->tpl->setVariable("NUMINFO", $numinfo); - } - - public function setPreviousNextLinks(): void - { + return $html; } /** @@ -631,13 +492,6 @@ public function getAsynch(): string return $this->tpl->get(); } - // - // New rendering - // - - // temporary flag - protected bool $new_rendering = false; - /** * Get legacy content @@ -840,104 +694,6 @@ protected function addRepoCommands(): void } } - public function getHTMLNew(): string - { - $access = $this->access; - $panel = null; - - $ctrl = $this->ctrl; - - if ($this->isRepositoryObject()) { - if (!$access->checkAccess("read", "", $this->getRefId())) { - return ""; - } - } - - $this->addRepoCommands(); - - switch ($this->getPresentation()) { - case self::PRES_SEC_LEG: - $panel = $this->factory->panel()->secondary()->legacy( - $this->specialCharsAsEntities($this->getTitle()), - $this->factory->legacy($this->getLegacyContent()) - ); - break; - - case self::PRES_MAIN_LEG: - $panel = $this->factory->panel()->standard( - $this->specialCharsAsEntities($this->getTitle()), - $this->factory->legacy($this->getLegacyContent()) - ); - break; - - case self::PRES_SEC_LIST: - $this->handleNavigation(); - $panel = $this->factory->panel()->secondary()->listing( - $this->specialCharsAsEntities($this->getTitle()), - $this->getListItemGroups() - ); - break; - - case self::PRES_MAIN_TILE: - case self::PRES_MAIN_LIST: - $this->handleNavigation(); - $panel = $this->factory->panel()->listing()->standard( - $this->specialCharsAsEntities($this->getTitle()), - $this->getListItemGroups() - ); - break; - } - - // check for empty list panel - if (in_array($this->getPresentation(), [self::PRES_SEC_LIST, self::PRES_MAIN_LIST], true) && - ($panel->getItemGroups() === [] || (count($panel->getItemGroups()) === 1 && $panel->getItemGroups()[0]->getItems() === []))) { - if ($this->getPresentation() === self::PRES_SEC_LIST) { - $panel = $this->factory->panel()->secondary()->legacy( - $this->specialCharsAsEntities($this->getTitle()), - $this->factory->legacy($this->getNoItemFoundContent()) - ); - } else { - $panel = $this->factory->panel()->standard( - $this->specialCharsAsEntities($this->getTitle()), - $this->factory->legacy($this->getNoItemFoundContent()) - ); - } - } - - $actions = $this->getActionsForPanel(); - if ($actions !== null) { - $panel = $panel->withActions($actions); - } - $viewControls = $this->getViewControlsForPanel(); - if ($viewControls !== [] && - ( - $panel instanceof StandardPanel || - $panel instanceof SecondaryListingPanel || - $panel instanceof SecondaryLegacyPanel || - $panel instanceof StandardListingPanel - ) - ) { - $panel = $panel->withViewControls($viewControls); - } - - if ($ctrl->isAsynch()) { - $html = $this->renderer->renderAsync([$panel, ...$this->modals]); - } else { - $html = $this->renderer->render([$panel, ...$this->modals]); - } - - - if ($ctrl->isAsynch()) { - $this->send($html); - } else { - // return incl. wrapping div with id - $html = '
' . - $html . '
'; - } - - return $html; - } - protected function getActionsForPanel(): ?Dropdown { // actions diff --git a/Services/COPage/PC/Question/class.ilPCQuestionGUI.php b/Services/COPage/PC/Question/class.ilPCQuestionGUI.php index c8b0d8d82b48..0c8d34d7e04d 100755 --- a/Services/COPage/PC/Question/class.ilPCQuestionGUI.php +++ b/Services/COPage/PC/Question/class.ilPCQuestionGUI.php @@ -158,10 +158,10 @@ public function insert(string $a_mode = "create"): void $ri = new ilRadioGroupInputGUI($this->lng->txt("tst_add_quest_cont_edit_mode"), "add_quest_cont_edit_mode"); $option_rte = new ilRadioOption( - $this->lng->txt('tst_add_quest_cont_edit_mode_RTE'), + $this->lng->txt('tst_add_quest_cont_edit_mode_plain'), assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_RTE ); - $option_rte->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_RTE_info')); + $option_rte->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_plain_info')); $ri->addOption($option_rte); $option_ipe = new ilRadioOption( diff --git a/Services/COPage/PC/Table/class.TableCommandActionHandler.php b/Services/COPage/PC/Table/class.TableCommandActionHandler.php index 6270026b34ab..126362eb8090 100644 --- a/Services/COPage/PC/Table/class.TableCommandActionHandler.php +++ b/Services/COPage/PC/Table/class.TableCommandActionHandler.php @@ -108,7 +108,7 @@ protected function insertCommand(array $body): Server\Response return $this->ui_wrapper->sendPage($this->page_gui, $updated); } - protected function setRowHeaderAndCharacteristic(\ilPCDataTable $tab, array $body): void + protected function setRowHeaderAndCharacteristic(\ilPCTable $tab, array $body): void { if ($body["has_row_header"] ?? false) { $tab->setHeaderRows(1); diff --git a/Services/COPage/css/content.css b/Services/COPage/css/content.css index 8b0dd0e2c9a5..80e0ab0a7eaf 100755 --- a/Services/COPage/css/content.css +++ b/Services/COPage/css/content.css @@ -218,8 +218,6 @@ a.ilc_section_AdvancedKnowledge::before { div.ilc_qanswer_Answer { padding-right: 10px; border-radius: 5px; - margin: 3px; - padding-left: 10px; } div.ilc_section_Attention, a.ilc_section_Attention { @@ -824,7 +822,7 @@ div.ilc_question_Standard { margin-top: 20px; margin-bottom: 10px; padding-top: 30px; - padding-right: 160px; + padding-right: 30px; } div.ilc_qover_StatusMessage { padding-bottom: 7px; diff --git a/Services/COPage/css/content.less b/Services/COPage/css/content.less index 894b78d561d9..bb762525318a 100644 --- a/Services/COPage/css/content.less +++ b/Services/COPage/css/content.less @@ -292,8 +292,6 @@ div.ilc_qanswer_Answer { padding-right: 10px; border-radius: 5px; - margin: 3px; - padding-left: 10px; } div.ilc_section_Attention @@ -1011,7 +1009,7 @@ div.ilc_question_Standard margin-top: 20px; margin-bottom: 10px; padding-top: 30px; - padding-right: 160px; + padding-right: 30px; } div.ilc_qover_StatusMessage diff --git a/Services/Calendar/classes/class.ilCalendarBlockGUI.php b/Services/Calendar/classes/class.ilCalendarBlockGUI.php index dd8d99d91a76..7a9c52a83301 100644 --- a/Services/Calendar/classes/class.ilCalendarBlockGUI.php +++ b/Services/Calendar/classes/class.ilCalendarBlockGUI.php @@ -268,25 +268,6 @@ public function executeCommand(): string return ''; } - public function fillDataSection(): void - { - if ($this->display_mode != "mmon") { - $this->setRowTemplate("tpl.pd_event_list.html", "Services/Calendar"); - - ilBlockGUI::fillDataSection(); - } else { - $tpl = new ilTemplate( - "tpl.calendar_block.html", - true, - true, - "Services/Calendar" - ); - - $this->addMiniMonth($tpl, true); - $this->setDataSection($tpl->get()); - } - } - public function getTargetGUIClassPath(): array { $target_class = array(); @@ -839,12 +820,6 @@ public function getModalForApp() exit(); } - // - // New rendering - // - - protected bool $new_rendering = true; - public function getViewControlsForPanel(): array { if ($this->getPresentation() == self::PRES_SEC_LEG) { diff --git a/Services/Calendar/classes/class.ilCalendarSelectionBlockGUI.php b/Services/Calendar/classes/class.ilCalendarSelectionBlockGUI.php index 200a7919aca0..ca2429fb0d76 100755 --- a/Services/Calendar/classes/class.ilCalendarSelectionBlockGUI.php +++ b/Services/Calendar/classes/class.ilCalendarSelectionBlockGUI.php @@ -1,7 +1,5 @@ ui->factory()->item()->standard($button); } - public function getHTMLNew(): string + public function getHTML(): string { if (empty($this->getData())) { return ''; } - return parent::getHTMLNew(); + return parent::getHTML(); } } diff --git a/Services/Calendar/templates/default/tpl.pd_event_list.html b/Services/Calendar/templates/default/tpl.pd_event_list.html deleted file mode 100644 index 58e7f6589153..000000000000 --- a/Services/Calendar/templates/default/tpl.pd_event_list.html +++ /dev/null @@ -1,4 +0,0 @@ -
- {VAL_DATE}
- {VAL_SHY_BUTTON} -
\ No newline at end of file diff --git a/Services/Container/Classification/class.ilClassificationBlockGUI.php b/Services/Container/Classification/class.ilClassificationBlockGUI.php index 5e94eab84c58..6e5945ae0e68 100644 --- a/Services/Container/Classification/class.ilClassificationBlockGUI.php +++ b/Services/Container/Classification/class.ilClassificationBlockGUI.php @@ -3,15 +3,18 @@ /** * This file is part of ILIAS, a powerful learning management system * published by ILIAS open source e-Learning e.V. + * * ILIAS is licensed with the GPL-3.0, * see https://www.gnu.org/licenses/gpl-3.0.en.html * You should have received a copy of said license along with the * source code, too. + * * If this is not the case or you just want to try ILIAS, you'll find * us at: * https://www.ilias.de * https://github.com/ILIAS-eLearning - */ + * + *********************************************************************/ use ILIAS\Container\Classification\StandardGUIRequest; @@ -395,13 +398,6 @@ protected function toggle(): void $this->ctrl->returnToParent($this); } - - // - // New rendering - // - - protected bool $new_rendering = true; - /** * Get sub item ids depending on container type that match the preselected * object ids diff --git a/Services/Dashboard/Block/classes/class.ilDashboardBlockGUI.php b/Services/Dashboard/Block/classes/class.ilDashboardBlockGUI.php index dfaf48a9221f..5f33d8a0ee8f 100644 --- a/Services/Dashboard/Block/classes/class.ilDashboardBlockGUI.php +++ b/Services/Dashboard/Block/classes/class.ilDashboardBlockGUI.php @@ -61,7 +61,6 @@ public function __construct() $this->object_cache = $DIC['ilObjDataCache']; $this->tree = $DIC->repositoryTree(); $this->objDefinition = $DIC['objDefinition']; - $this->new_rendering = true; $this->rbacsystem = $DIC->rbac()->system(); $this->favourites_manager = new ilFavouritesManager(); $this->parent = $this->ctrl->getCurrentClassPath()[0] ?? ''; @@ -220,7 +219,7 @@ public function getHTML(): string $this->addCommandActions(); $this->setData($this->getItemGroups()); - return parent::getHTMLNew(); + return parent::getHTML(); } /** diff --git a/Services/Dashboard/ItemsBlock/classes/class.ilDashboardSidePanelSettingsRepository.php b/Services/Dashboard/ItemsBlock/classes/class.ilDashboardSidePanelSettingsRepository.php index 3f03064575a9..0bd83b190d52 100644 --- a/Services/Dashboard/ItemsBlock/classes/class.ilDashboardSidePanelSettingsRepository.php +++ b/Services/Dashboard/ItemsBlock/classes/class.ilDashboardSidePanelSettingsRepository.php @@ -61,10 +61,17 @@ public function setPositions(array $positions): void public function getPositions(): array { $positions = $this->setting->get('side_panel_positions', ''); + $modules = []; if ($positions !== '') { - return unserialize($positions, ['allowed_classes' => false]); + $modules = unserialize($positions, ['allowed_classes' => false]); } - return $this->getValidModules(); + $all_modules = $this->getValidModules(); + foreach ($all_modules as $mod) { + if (!in_array($mod, $modules, true)) { + $modules[] = $mod; + } + } + return $modules; } protected function isValidModule(string $mod): bool diff --git a/Services/Form/classes/class.ilTextWizardInputGUI.php b/Services/Form/classes/class.ilTextWizardInputGUI.php index 40129b3008c3..59f0758ee8e5 100755 --- a/Services/Form/classes/class.ilTextWizardInputGUI.php +++ b/Services/Form/classes/class.ilTextWizardInputGUI.php @@ -1,7 +1,5 @@ setAlert($lng->txt("msg_wrong_format")); return false; } + } elseif ($this->getMaxLength() && mb_strlen($value) > $this->getMaxLength()) { + $this->setAlert($lng->txt("msg_input_char_limit_max")); + return false; } } } elseif ($this->getRequired()) { diff --git a/Services/InfoScreen/classes/class.ilInfoScreenGUI.php b/Services/InfoScreen/classes/class.ilInfoScreenGUI.php index 44a699cae489..10161947caae 100644 --- a/Services/InfoScreen/classes/class.ilInfoScreenGUI.php +++ b/Services/InfoScreen/classes/class.ilInfoScreenGUI.php @@ -1,7 +1,5 @@ addSection($lng->txt("description")); $this->addProperty("", nl2br($description)); - }*/ + } // general section $this->addSection($lng->txt("meta_general")); diff --git a/Services/Mail/classes/class.ilPDMailBlockGUI.php b/Services/Mail/classes/class.ilPDMailBlockGUI.php index ac37f246f781..0bfff4e563e9 100755 --- a/Services/Mail/classes/class.ilPDMailBlockGUI.php +++ b/Services/Mail/classes/class.ilPDMailBlockGUI.php @@ -120,56 +120,6 @@ protected function getMails(): void $this->max_count = count($this->mails); } - public function fillDataSection(): void - { - if ($this->mails !== []) { - $this->setRowTemplate("tpl.pd_mail_row.html", "Services/Mail"); - parent::fillDataSection(); - } else { - $this->setEnableNumInfo(false); - $this->setDataSection($this->getOverview()); - } - } - - public function fillRow(array $a_set): void - { - $user = ilMailUserCache::getUserObjectById((int) $a_set['sender_id']); - - $this->tpl->touchBlock('usr_image_space'); - if ($user && $user->getId() !== ANONYMOUS_USER_ID) { - $this->tpl->setVariable('PUBLIC_NAME_LONG', $user->getPublicName()); - $this->tpl->setVariable('IMG_SENDER', $user->getPersonalPicturePath('xxsmall')); - $this->tpl->setVariable('ALT_SENDER', htmlspecialchars($user->getPublicName())); - } elseif (!$user instanceof ilObjUser) { - $this->tpl->setVariable( - 'PUBLIC_NAME_LONG', - trim(($a_set['import_name'] ?? '') . ' (' . $this->lng->txt('user_deleted') . ')') - ); - - $this->tpl->setCurrentBlock('image_container'); - $this->tpl->touchBlock('image_container'); - $this->tpl->parseCurrentBlock(); - } else { - $this->tpl->setVariable('PUBLIC_NAME_LONG', ilMail::_getIliasMailerName()); - $this->tpl->setVariable('IMG_SENDER', ilUtil::getImagePath('logo/HeaderIconAvatar.svg')); - $this->tpl->setVariable('ALT_SENDER', htmlspecialchars(ilMail::_getIliasMailerName())); - } - - $this->tpl->setVariable( - 'NEW_MAIL_DATE', - ilDatePresentation::formatDate(new ilDate($a_set['send_time'], IL_CAL_DATE)) - ); - - $this->tpl->setVariable( - 'NEW_MAIL_SUBJ', - htmlentities($a_set['m_subject'], ENT_NOQUOTES, 'UTF-8') - ); - $this->ctrl->setParameter($this, 'mobj_id', $this->inbox); - $this->ctrl->setParameter($this, 'mail_id', $a_set['mail_id']); - $this->tpl->setVariable('NEW_MAIL_LINK_READ', $this->ctrl->getLinkTarget($this, 'showMail')); - $this->ctrl->clearParameters($this); - } - protected function getOverview(): string { return '
' . (count($this->mails)) . " " . $this->lng->txt("mails_pl") . "
"; @@ -260,12 +210,6 @@ protected function preloadData(array $data): void ilMailUserCache::preloadUserObjects($usr_ids); } - // - // New rendering - // - - protected bool $new_rendering = true; - protected function getListItemForData(array $data): ?Item { $f = $this->ui->factory(); diff --git a/Services/Mail/templates/default/tpl.pd_mail_row.html b/Services/Mail/templates/default/tpl.pd_mail_row.html deleted file mode 100644 index fb3c0e599965..000000000000 --- a/Services/Mail/templates/default/tpl.pd_mail_row.html +++ /dev/null @@ -1,22 +0,0 @@ -
- -
- - {ALT_SENDER} - -
- -
- -
{PUBLIC_NAME_SHORT}
- - - -
{PUBLIC_NAME_LONG}
-
{NEW_MAIL_DATE}
- -
-
-
diff --git a/Services/News/classes/class.ilNewsForContextBlockGUI.php b/Services/News/classes/class.ilNewsForContextBlockGUI.php index b3d1cd79a21f..3651e0a6211b 100755 --- a/Services/News/classes/class.ilNewsForContextBlockGUI.php +++ b/Services/News/classes/class.ilNewsForContextBlockGUI.php @@ -38,7 +38,6 @@ class ilNewsForContextBlockGUI extends ilBlockGUI protected bool $dynamic = false; protected ilNewsCache $acache; protected bool $show_view_selection; - protected bool $new_rendering = true; /** * @var false|mixed|string|null @@ -97,10 +96,7 @@ public function __construct() self::$st_data = ilNewsItem::prepareNewsDataFromCache($cres); $this->cache_hit = true; } - if ($this->getDynamic() && !$this->cache_hit) { - $this->dynamic = true; - $data = []; - } elseif (!empty(self::$st_data)) { + if (!empty(self::$st_data)) { $data = self::$st_data; } else { $data = $this->getNewsData(); @@ -216,17 +212,6 @@ public function executeCommand() } } - public function fillDataSection(): void - { - if ($this->dynamic) { - $this->setDataSection($this->getDynamicReload()); - } elseif (count($this->getData()) > 0) { - parent::fillDataSection(); - } else { - $this->setDataSection($this->getOverview()); - } - } - public function getHTML(): string { global $DIC; @@ -372,39 +357,6 @@ public function handleView(): void } } - /** - * get flat list for dashboard - */ - public function fillRow(array $a_set): void - { - $info = $this->getInfoForData($a_set); - - $this->tpl->setCurrentBlock("long"); - $this->tpl->setVariable("VAL_CREATION_DATE", $info["creation_date"]); - $this->tpl->parseCurrentBlock(); - - if ($info["ref_id"] > 0) { - $this->tpl->setCurrentBlock("news_context"); - $this->tpl->setVariable("TYPE", $info["type_txt"]); - $this->tpl->setVariable("IMG_TYPE", $info["type_icon"]); - $this->tpl->setVariable("TITLE", $info["obj_title"]); - if ($info["user_read"] > 0) { - $this->tpl->setVariable("TITLE_CLASS", 'class="light"'); - } - - $this->tpl->parseCurrentBlock(); - } - - // title - $this->tpl->setVariable("VAL_TITLE", $info["news_title"]); - - if ($info["user_read"] > 0) { - $this->tpl->setVariable("A_CLASS", 'class="light"'); - } - - $this->tpl->setVariable("HREF_SHOW", $info["url"]); - } - public function getInfoForData(array $news): array { $ilCtrl = $this->ctrl; @@ -1249,40 +1201,6 @@ public function showFeedUrl(): string return $this->ui->renderer()->render($panel); } - public function getDynamic(): bool - { - $ilCtrl = $this->ctrl; - $ilUser = $this->user; - - // @todo: enable js loading - if ($this->new_rendering) { - return false; - } - - if ($ilCtrl->getCmd() === "hideNotifications" || - $ilCtrl->getCmd() === "showNotifications") { - return false; - } - - if ($ilCtrl->getCmdClass() !== "ilcolumngui" && $ilCtrl->getCmd() !== "enableJS") { - $sess_feed_js = ""; - if (ilSession::get("il_feed_js") != "") { - $sess_feed_js = ilSession::get("il_feed_js"); - } - - if ($sess_feed_js !== "n" && - ($ilUser->getPref("il_feed_js") !== "n" || $sess_feed_js === "y")) { - // do not get feed dynamically, if cache hit is given. - // if (!$this->feed->checkCacheHit()) - // { - return true; - // } - } - } - - return false; - } - public function getDynamicReload(): string { $ilCtrl = $this->ctrl; @@ -1351,12 +1269,6 @@ public function enableJS(): void $this->send($this->getHTML()); } - // - // New rendering - // - - - protected function getListItemForData(array $data): ?\ILIAS\UI\Component\Item\Item { if ((int) ($data["id"] ?? 0) === 0) { diff --git a/Services/News/classes/class.ilPDNewsBlockGUI.php b/Services/News/classes/class.ilPDNewsBlockGUI.php index 888cc5232143..23f4f5050ee5 100755 --- a/Services/News/classes/class.ilPDNewsBlockGUI.php +++ b/Services/News/classes/class.ilPDNewsBlockGUI.php @@ -64,18 +64,11 @@ public function __construct() $this->cache_hit = true; } - if (!$this->cache_hit && $this->getDynamic()) { - $this->dynamic = true; - $data = []; - } else { - // do not ask two times for the data (e.g. if user displays a - // single item on the personal desktop and the news block is - // displayed at the same time) - if (empty(self::$st_data)) { - self::$st_data = $this->getNewsData(); - } - $data = self::$st_data; + + if (empty(self::$st_data)) { + self::$st_data = $this->getNewsData(); } + $data = self::$st_data; $this->setTitle($lng->txt("news_internal_news")); $this->setRowTemplate("tpl.block_row_news_for_context.html", "Services/News"); @@ -148,18 +141,6 @@ public function executeCommand() } } - public function fillDataSection(): void - { - if ($this->dynamic) { - $this->setDataSection($this->getDynamicReload()); - } elseif (count($this->getData()) > 0) { - parent::fillDataSection(); - } else { - $this->setEnableNumInfo(false); - $this->setDataSection($this->getOverview()); - } - } - public function getHTML(): string { $ilCtrl = $this->ctrl; diff --git a/Services/Object/classes/class.ilObjectMetaDataBlockGUI.php b/Services/Object/classes/class.ilObjectMetaDataBlockGUI.php index 27f8693cfb49..801925b75424 100644 --- a/Services/Object/classes/class.ilObjectMetaDataBlockGUI.php +++ b/Services/Object/classes/class.ilObjectMetaDataBlockGUI.php @@ -1,7 +1,5 @@ $cmd(); } - /** - * Fill data section - */ - public function fillDataSection(): void - { - $this->setDataSection($this->getLegacyContent()); - } - - // - // New rendering - // - - protected bool $new_rendering = true; - - /** * @inheritdoc */ diff --git a/Services/PrivacySecurity/classes/class.ilSecuritySettings.php b/Services/PrivacySecurity/classes/class.ilSecuritySettings.php index 98d66019960c..7a7f28d41a70 100644 --- a/Services/PrivacySecurity/classes/class.ilSecuritySettings.php +++ b/Services/PrivacySecurity/classes/class.ilSecuritySettings.php @@ -1,19 +1,22 @@ setTitle($a_title); $this->allow_moving = false; - $this->new_rendering = true; } /** @@ -89,16 +88,6 @@ public function executeCommand(): void } } - public function getHTML(): string - { - return parent::getHTML(); - } - - public function fillDataSection(): void - { - $this->setDataSection($this->getLegacyContent()); - } - /** * @inheritdoc */ diff --git a/Services/Style/Content/Service/class.InternalService.php b/Services/Style/Content/Service/class.InternalService.php index cd65110b7b76..5bd625c91daa 100644 --- a/Services/Style/Content/Service/class.InternalService.php +++ b/Services/Style/Content/Service/class.InternalService.php @@ -1,7 +1,5 @@ - */ class InternalService { - protected InternalDataService $data; - protected InternalRepoService $repo; - protected InternalDomainService $domain; - protected InternalGUIService $gui; + protected static array $instance = []; + protected Container $DIC; public function __construct(Container $DIC) { - $this->data = new InternalDataService(); - - $this->repo = new InternalRepoService( - $this->data(), - $DIC->database(), - $DIC->filesystem()->web(), - $DIC->upload() - ); - $this->domain = new InternalDomainService( - $DIC, - $this->repo, - $this->data - ); - $this->gui = new InternalGUIService( - $DIC, - $this->data, - $this->domain - ); + $this->DIC = $DIC; } public function data(): InternalDataService { - return $this->data; + return self::$instance["data"] ??= new InternalDataService(); } public function repo(): InternalRepoService { - return $this->repo; + return self::$instance["repo"] ??= new InternalRepoService( + $this->data(), + $this->DIC->database(), + $this->DIC->filesystem()->web(), + $this->DIC->upload() + ); } public function domain(): InternalDomainService { - return $this->domain; + return self::$instance["domain"] ??= new InternalDomainService( + $this->DIC, + $this->repo(), + $this->data() + ); } public function gui(): InternalGUIService { - return $this->gui; + return self::$instance["gui"] ??= new InternalGUIService( + $this->DIC, + $this->data(), + $this->domain() + ); } } diff --git a/Services/Style/Content/Service/class.Service.php b/Services/Style/Content/Service/class.Service.php index 9a1bc4d16d86..bc8617837203 100644 --- a/Services/Style/Content/Service/class.Service.php +++ b/Services/Style/Content/Service/class.Service.php @@ -1,7 +1,5 @@ - */ class Service { protected Container $DIC; - protected InternalService $internal; - protected DomainService $domain; - protected GUIService $gui; + protected static array $instance = []; public function __construct(Container $DIC) { $this->DIC = $DIC; - - $this->internal = new InternalService($this->DIC); - $this->gui = new GUIService( - $this->internal - ); - $this->domain = new DomainService( - $this->internal - ); } - /** - * Internal service, do not use in other components - */ public function internal(): InternalService { - return $this->internal; + return self::$instance["internal"] ??= new InternalService($this->DIC); } public function gui(): GUIService { - return $this->gui; + return self::$instance["gui"] ??= new GUIService($this->internal()); } public function domain(): DomainService { - return $this->domain; + return self::$instance["domain"] ??= new DomainService($this->internal()); } } diff --git a/Services/Tasks/classes/class.ilPDTasksBlockGUI.php b/Services/Tasks/classes/class.ilPDTasksBlockGUI.php index 3a7cf11983fa..977d4eca83e4 100644 --- a/Services/Tasks/classes/class.ilPDTasksBlockGUI.php +++ b/Services/Tasks/classes/class.ilPDTasksBlockGUI.php @@ -88,26 +88,6 @@ public function executeCommand() return $this->$cmd(); } - /** - * Fill data section - */ - public function fillDataSection(): void - { - global $DIC; - $collector = $DIC->task()->derived()->factory()->collector(); - - $this->tasks = $collector->getEntries($this->user->getId()); - - if (count($this->tasks) > 0) { - $this->setRowTemplate("tpl.pd_tasks.html", "Services/Tasks"); - $this->getListRowData(); - parent::fillDataSection(); - } else { - $this->setEnableNumInfo(false); - $this->setDataSection($this->getOverview()); - } - } - /** * Get list data. @@ -131,81 +111,6 @@ public function getListRowData(): void $this->setData($data); } - /** - * get flat list for personal desktop - */ - public function fillRow(array $a_set): void - { - global $DIC; - - $factory = $DIC->ui()->factory(); - $renderer = $DIC->ui()->renderer(); - $lng = $this->lng; - - $info_screen = new ilInfoScreenGUI($this); - $info_screen->setFormAction("#"); - $info_screen->addSection($lng->txt("")); - //$toolbar = new ilToolbarGUI(); - - $info_screen->addProperty( - $lng->txt("task_task"), - $a_set["title"] - ); - - if ($a_set["ref_id"] > 0) { - $obj_id = ilObject::_lookupObjId($a_set["ref_id"]); - $obj_type = ilObject::_lookupType($obj_id); - - $url = 0 === $a_set['url'] ? ilLink::_getStaticLink($a_set["ref_id"]) : $a_set['url']; - $link = $factory->button()->shy(ilObject::_lookupTitle($obj_id), $url); - - $info_screen->addProperty( - $lng->txt("obj_" . $obj_type), - $renderer->render($link) - ); - } - - if ($a_set["wsp_id"] > 0) { - $wst = new ilWorkspaceTree($this->user->getId()); - $obj_id = $wst->lookupObjectId($a_set["wsp_id"]); - $obj_type = ilObject::_lookupType($obj_id); - - $url = 0 === $a_set['url'] ? ilLink::_getStaticLink($a_set["wsp_id"]) : $a_set['url']; - $link = $factory->button()->shy(ilObject::_lookupTitle($obj_id), $url); - - $info_screen->addProperty( - $lng->txt("obj_" . $obj_type), - $renderer->render($link) - ); - } - - if ($a_set["starting_time"] > 0) { - $start = new ilDateTime($a_set["starting_time"], IL_CAL_UNIX); - $info_screen->addProperty( - $lng->txt("task_start"), - ilDatePresentation::formatDate($start) - ); - } - - if ($a_set["deadline"] > 0) { - $end = new ilDateTime($a_set["deadline"], IL_CAL_UNIX); - $info_screen->addProperty( - $lng->txt("task_deadline"), - ilDatePresentation::formatDate($end) - ); - } - - $modal = $factory->modal()->roundtrip( - $lng->txt("task_details"), - $factory->legacy($info_screen->getHTML()) - ) - ->withCancelButtonLabel($lng->txt("close")); - $button1 = $factory->button()->shy($a_set["title"], '#') - ->withOnClick($modal->getShowSignal()); - - $this->tpl->setVariable("TITLE", $renderer->render([$button1, $modal])); - } - /** * Get overview. */ @@ -216,16 +121,10 @@ public function getOverview(): string return '
' . (count($this->tasks)) . " " . $lng->txt("task_derived_tasks") . "
"; } - // - // New rendering - // - - protected bool $new_rendering = true; - /** * @inheritdoc */ - public function getHTMLNew(): string + public function getHTML(): string { global $DIC; $collector = $DIC->task()->derived()->factory()->collector(); @@ -234,7 +133,7 @@ public function getHTMLNew(): string $this->getListRowData(); - return parent::getHTMLNew(); + return parent::getHTML(); } /** diff --git a/Services/Tasks/templates/default/tpl.pd_tasks.html b/Services/Tasks/templates/default/tpl.pd_tasks.html deleted file mode 100644 index d9b4a925a933..000000000000 --- a/Services/Tasks/templates/default/tpl.pd_tasks.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {TITLE} -
\ No newline at end of file diff --git a/Services/Tracking/classes/repository_statistics/class.ilTrMatrixTableGUI.php b/Services/Tracking/classes/repository_statistics/class.ilTrMatrixTableGUI.php index 4d0aa0b96016..90b1993d49fc 100644 --- a/Services/Tracking/classes/repository_statistics/class.ilTrMatrixTableGUI.php +++ b/Services/Tracking/classes/repository_statistics/class.ilTrMatrixTableGUI.php @@ -505,6 +505,21 @@ public function getItems( } } + /* + * ilTrQuery does not read out any information about org units + * (nor should it), so it needs to be added here. + */ + if (in_array('org_units', $a_user_fields)) { + foreach (($data['set'] ?? []) as $key => $usr_data) { + if (!isset($usr_data['usr_id'])) { + continue; + } + $usr_id = (int) $usr_data['usr_id']; + $org_units = ilOrgUnitPathStorage::getTextRepresentationOfUsersOrgUnits($usr_id); + $data["set"][$key]['org_units'] = $org_units; + } + } + $this->setMaxCount($data["cnt"] ?? 0); $this->setData($data["set"] ?? []); return $collection["object_ids"] ?? []; diff --git a/Services/Tracking/classes/repository_statistics/class.ilTrObjectUsersPropsTableGUI.php b/Services/Tracking/classes/repository_statistics/class.ilTrObjectUsersPropsTableGUI.php index 6bfa4360a975..d48fc5689022 100644 --- a/Services/Tracking/classes/repository_statistics/class.ilTrObjectUsersPropsTableGUI.php +++ b/Services/Tracking/classes/repository_statistics/class.ilTrObjectUsersPropsTableGUI.php @@ -224,6 +224,22 @@ public function getItems(): void $this->user_fields ); } + + /* + * ilTrQuery does not read out any information about org units + * (nor should it), so it needs to be added here. + */ + if (in_array('org_units', $additional_fields)) { + foreach (($tr_data['set'] ?? []) as $key => $data) { + if (!isset($data['usr_id'])) { + continue; + } + $usr_id = (int) $data['usr_id']; + $org_units = ilOrgUnitPathStorage::getTextRepresentationOfUsersOrgUnits($usr_id); + $tr_data["set"][$key]['org_units'] = $org_units; + } + } + $this->setMaxCount($tr_data["cnt"]); $this->setData($tr_data["set"]); } diff --git a/Services/User/classes/Setup/class.ilUserDB90.php b/Services/User/classes/Setup/class.ilUserDB90.php index 79f1ac240388..56d8becc1429 100644 --- a/Services/User/classes/Setup/class.ilUserDB90.php +++ b/Services/User/classes/Setup/class.ilUserDB90.php @@ -120,4 +120,28 @@ public function step_9(): void $query = 'DELETE FROM settings WHERE module="common" AND keyword="user_adm_alpha_nav";'; $this->db->manipulate($query); } + + public function step_10(): void + { + $query = 'SELECT value FROM settings WHERE module = %s AND keyword = %s'; + $res = $this->db->queryF( + $query, + [\ilDBConstants::T_TEXT, \ilDBConstants::T_TEXT], + ['common', 'ps_login_max_attempts'] + ); + + // We should adjust the usr_data values, even if the "Max. Login Attempts" are currently not set + $max_login_attempts = min( + (int) ($this->db->fetchAssoc($res)['value'] ?? ilSecuritySettings::MAX_LOGIN_ATTEMPTS), + ilSecuritySettings::MAX_LOGIN_ATTEMPTS + ); + + $max_login_attempts_exceeded = $max_login_attempts + 1; + + $this->db->manipulateF( + 'UPDATE usr_data SET login_attempts = %s WHERE login_attempts > %s', + [\ilDBConstants::T_INTEGER, \ilDBConstants::T_INTEGER], + [$max_login_attempts_exceeded, $max_login_attempts_exceeded] + ); + } } diff --git a/Services/User/classes/class.ilObjUserFolderGUI.php b/Services/User/classes/class.ilObjUserFolderGUI.php index 003cb0df9f91..6089bbce2195 100755 --- a/Services/User/classes/class.ilObjUserFolderGUI.php +++ b/Services/User/classes/class.ilObjUserFolderGUI.php @@ -2314,6 +2314,9 @@ protected function initFormGeneralSettings(): void 'login_max_attempts' ); $text->setInfo($this->lng->txt('ps_login_max_attempts_info')); + $text->allowDecimals(false); + $text->setMinValue(1); + $text->setMaxValue(ilSecuritySettings::MAX_LOGIN_ATTEMPTS); $text->setSize(1); $text->setMaxLength(2); $this->form->addItem($text); diff --git a/lang/ilias_de.lang b/lang/ilias_de.lang index 37c3c7b1300e..c6d59f814e97 100644 --- a/lang/ilias_de.lang +++ b/lang/ilias_de.lang @@ -1269,6 +1269,8 @@ assessment#:#tst_add_quest_cont_edit_mode_IPE#:#Unformatierter Text für Fragen assessment#:#tst_add_quest_cont_edit_mode_IPE_info#:#Bietet keine Formatierung von Text in Fragen und Antworten, erlaubt aber Gestaltung der Rückmeldungen und Lösungshinweise mit ILIAS-Seiteneditor und Wiederverwendung bei Fragen in ILIAS-Lernmodulen. assessment#:#tst_add_quest_cont_edit_mode_RTE#:#Rich-Text-Editor (TinyMCE) für das Editieren der Fragen, Antworten, Rückmeldungen und Lösungshinweisen assessment#:#tst_add_quest_cont_edit_mode_RTE_info#:#Erlaubt formatierten Text für Fragen, Antworten, Rückmeldungen und Lösungshinweise. Rückmeldungen und Lösungshinweise werden aber beim Einbinden von Fragen in ILIAS-Lernmodule nicht übernommen. +assessment#:#tst_add_quest_cont_edit_mode_plain#:#Unformatierter Text +assessment#:#tst_add_quest_cont_edit_mode_plain_info#:#Bietet keine Formatierung von Text in Fragen, Antworten, Rückmeldungen und Lösungshinweisen. assessment#:#tst_addit_passes_blocked_after_passed_msg#:#Sie haben den Test bestanden. Der Test kann nicht noch einmal gestartet werden. assessment#:#tst_all_test_competences#:#Alle Test-Kompetenzen assessment#:#tst_all_user_data_deleted#:#Die Daten aller Testteilnehmer wurden gelöscht! diff --git a/lang/ilias_en.lang b/lang/ilias_en.lang index faa46168e9c2..85ed2384861e 100644 --- a/lang/ilias_en.lang +++ b/lang/ilias_en.lang @@ -1269,6 +1269,8 @@ assessment#:#tst_add_quest_cont_edit_mode_IPE#:#Use plain text for questions and assessment#:#tst_add_quest_cont_edit_mode_IPE_info#:#No formatting of text in question and answers. No use of LaTex either. But feedback and hints can be reused when question is embedded in ILIAS learning module. assessment#:#tst_add_quest_cont_edit_mode_RTE#:#Use Rich-Text-Editor (TinyMCE) for editing questions and answers, feedbacks and hints assessment#:#tst_add_quest_cont_edit_mode_RTE_info#:#Allows text formatting of questions, answers, feedbacks and hints. But feedback and hints cannot be reused when question is embedded in ILIAS learning module. +assessment#:#tst_add_quest_cont_edit_mode_plain#:#Use plain text +assessment#:#tst_add_quest_cont_edit_mode_plain_info#:#No formatting of text in question, answers, feedback, and hints. assessment#:#tst_addit_passes_blocked_after_passed_msg#:#You have passed the test. The test cannot be started again. assessment#:#tst_all_test_competences#:#All Test Competence assessment#:#tst_all_user_data_deleted#:#All user data for this test has been removed! @@ -14664,7 +14666,7 @@ registration#:#reg_direct_info#:#New user registration requests are automaticall registration#:#reg_disabled#:#No Registration Possible registration#:#reg_domain#:#Domain registration#:#reg_domain_already_assigned_p#:#The domains '%s' were already entered for another role. -registration#:#reg_domain_already_assigned_s#:#The domain '%s' was already entered for another role. +registration#:#reg_domain_already_assigned_s#:#The domain '%s' was already entered for another role. registration#:#reg_email#:#Automatic Role Assignment registration#:#reg_email_domains#:#The following e-mail address domains are valid: %s registration#:#reg_email_domains_code#:#With a registration code any E-Mail-Address is valid. diff --git a/src/ResourceStorage/Flavour/Engine/ImagickEngineWithOptionalFFMpeg.php b/src/ResourceStorage/Flavour/Engine/ImagickEngineWithOptionalFFMpeg.php index e34372d8f61e..0ec4d30eac9b 100644 --- a/src/ResourceStorage/Flavour/Engine/ImagickEngineWithOptionalFFMpeg.php +++ b/src/ResourceStorage/Flavour/Engine/ImagickEngineWithOptionalFFMpeg.php @@ -25,6 +25,9 @@ */ class ImagickEngineWithOptionalFFMpeg extends ImagickEngine { + /** + * @readonly + */ private FFMpegEngine $ffmpeg; protected array $supported; diff --git a/src/ResourceStorage/Flavour/FlavourBuilder.php b/src/ResourceStorage/Flavour/FlavourBuilder.php index b90d1cb31978..af9d1d62470d 100644 --- a/src/ResourceStorage/Flavour/FlavourBuilder.php +++ b/src/ResourceStorage/Flavour/FlavourBuilder.php @@ -19,6 +19,9 @@ namespace ILIAS\ResourceStorage\Flavour; +use ILIAS\ResourceStorage\Flavour\Machine\FlavourMachine; +use ILIAS\ResourceStorage\Resource\StorableResource; +use ILIAS\ResourceStorage\StorageHandler\StorageHandler; use ILIAS\Filesystem\Stream\Streams; use ILIAS\ResourceStorage\Consumer\StreamAccess\StreamAccess; use ILIAS\ResourceStorage\Flavour\Definition\FlavourDefinition; @@ -40,24 +43,14 @@ class FlavourBuilder public const VARIANT_NAME_MAX_LENGTH = 768; private array $current_revision_cache = []; private array $resources_cache = []; - private FlavourRepository $flavour_resource_repository; - private Factory $flavour_machine_factory; - private ResourceBuilder $resource_builder; - private StorageHandlerFactory $storage_handler_factory; - private StreamAccess $stream_access; public function __construct( - FlavourRepository $flavour_resource_repository, - Factory $flavour_machine_factory, - ResourceBuilder $resource_builder, - StorageHandlerFactory $storage_handler_factory, - StreamAccess $stream_access + private readonly FlavourRepository $flavour_resource_repository, + private readonly Factory $flavour_machine_factory, + private readonly ResourceBuilder $resource_builder, + private readonly StorageHandlerFactory $storage_handler_factory, + private readonly StreamAccess $stream_access ) { - $this->flavour_resource_repository = $flavour_resource_repository; - $this->flavour_machine_factory = $flavour_machine_factory; - $this->resource_builder = $resource_builder; - $this->storage_handler_factory = $storage_handler_factory; - $this->stream_access = $stream_access; } public function has( @@ -123,12 +116,10 @@ private function read( $storage = $this->getStorageHandler($flavour); $storage->deleteFlavour($current_revision, $flavour); // run Machine - $flavour = $this->runMachine($rid, $definition, $flavour); - } else { - $flavour = $this->populateFlavourWithExistingStreams($flavour); + return $this->runMachine($rid, $definition, $flavour); } - return $flavour; + return $this->populateFlavourWithExistingStreams($flavour); } private function new(FlavourDefinition $definition, ResourceIdentification $rid): Flavour @@ -197,7 +188,7 @@ private function populateFlavourWithExistingStreams(Flavour $flavour): Flavour } // DEFINITIONS AND MACHINES - private function checkDefinitionForMachine(FlavourDefinition $definition, Machine\FlavourMachine $machine): void + private function checkDefinitionForMachine(FlavourDefinition $definition, FlavourMachine $machine): void { if (!$machine->canHandleDefinition($definition)) { throw new \InvalidArgumentException("FlavourDefinition not supported by machine"); @@ -222,7 +213,7 @@ public function testDefinition( $this->checkDefinition($definition); $machine = $this->flavour_machine_factory->get($definition); $this->checkDefinitionForMachine($definition, $machine); - } catch (\Throwable $e) { + } catch (\Throwable) { return false; } if ($machine instanceof NullMachine) { @@ -235,7 +226,7 @@ public function testDefinition( $current_revision = $this->getResource($rid)->getCurrentRevision(); $suffix = $current_revision->getInformation()->getSuffix(); $size = $current_revision->getInformation()->getSize(); - if($size > $engine->getSizeLimitInBytes()) { + if ($size > $engine->getSizeLimitInBytes()) { return false; } @@ -266,26 +257,31 @@ protected function runMachine( // Run Machine and get Streams $storable_streams = []; - foreach ( - $machine->processStream( - $revision->getInformation(), - $stream, - $definition - ) as $result - ) { - $generated_stream = $result->getStream(); - if ($result->isStoreable()) { - // Collect Streams to store persistently - $storable_streams[$result->getIndex()] = $generated_stream; + try { + foreach ( + $machine->processStream( + $revision->getInformation(), + $stream, + $definition + ) as $result + ) { + $generated_stream = $result->getStream(); + if ($result->isStoreable()) { + // Collect Streams to store persistently + $storable_streams[$result->getIndex()] = $generated_stream; + } + + $cloned_stream = Streams::ofString((string) $generated_stream); + + $flavour = $this->stream_access->populateFlavour( + $flavour, + $cloned_stream, + $result->getIndex() + ); } - - $cloned_stream = Streams::ofString((string) $generated_stream); - - $flavour = $this->stream_access->populateFlavour( - $flavour, - $cloned_stream, - $result->getIndex() - ); + } catch (\Throwable) { + // error while processing stream, cannot process + return $flavour; } // Store Streams persistently if needed @@ -308,21 +304,20 @@ private function getCurrentRevision(Flavour $flavour): Revision return $this->current_revision_cache[$rid] = $this->getResourceOfFlavour($flavour)->getCurrentRevision(); } - private function getResource(ResourceIdentification $rid): \ILIAS\ResourceStorage\Resource\StorableResource + private function getResource(ResourceIdentification $rid): StorableResource { $rid_string = $rid->serialize(); - if (isset($this->resources_cache[$rid_string])) { - return $this->resources_cache[$rid_string]; - } - return $this->resources_cache[$rid_string] = $this->resource_builder->get($rid); + return $this->resources_cache[$rid_string] ?? ($this->resources_cache[$rid_string] = $this->resource_builder->get( + $rid + )); } - private function getResourceOfFlavour(Flavour $flavour): \ILIAS\ResourceStorage\Resource\StorableResource + private function getResourceOfFlavour(Flavour $flavour): StorableResource { return $this->getResource($flavour->getResourceID()); } - private function getStorageHandler(Flavour $flavour): \ILIAS\ResourceStorage\StorageHandler\StorageHandler + private function getStorageHandler(Flavour $flavour): StorageHandler { return $this->storage_handler_factory->getHandlerForResource($this->getResourceOfFlavour($flavour)); } diff --git a/src/ResourceStorage/Flavour/Machine/DefaultMachines/Extract/PDF.php b/src/ResourceStorage/Flavour/Machine/DefaultMachines/Extract/PDF.php index da00782ba06e..9f9fef8057b2 100644 --- a/src/ResourceStorage/Flavour/Machine/DefaultMachines/Extract/PDF.php +++ b/src/ResourceStorage/Flavour/Machine/DefaultMachines/Extract/PDF.php @@ -21,6 +21,7 @@ namespace ILIAS\ResourceStorage\Flavour\Machine\DefaultMachines\Extract; use ILIAS\ResourceStorage\Flavour\Definition\PagesToExtract; +use ILIAS\Filesystem\Stream\Stream; /** * @author Fabian Schmid @@ -32,4 +33,38 @@ public function getResolution(): int return 96; } + public function readImage(\Imagick $img, Stream $stream, PagesToExtract $definition): \Imagick + { + // Using ghostscript to extract pages from PDFs is faster and more reliable. If ghostscript is available, use it. + if (defined('PATH_TO_GHOSTSCRIPT') && PATH_TO_GHOSTSCRIPT !== "") { + // extract one single page as image using ghostscript in cli and add it to the imagick object + $file_path = $stream->getMetadata()['uri']; + $start_page = 1; + + $cmd = PATH_TO_GHOSTSCRIPT . " -q -dNODISPLAY -dNOSAFER -c \"($file_path) (r) file runpdfbegin pdfpagecount = quit\";"; + $pages_in_file = (int) shell_exec($cmd); + + $end_page = min($pages_in_file, $definition->getMaxPages()); + for ($i = $start_page; $i <= $end_page; $i++) { + // run ghostscript in cli and return the image to stdout + $cmd = PATH_TO_GHOSTSCRIPT . " -dNOPAUSE -sDEVICE=png16m -r" + . $this->getResolution() + . " -dFirstPage=" . $i + . " -dLastPage=" . $i . + " -sOutputFile=- -q " . escapeshellarg((string) $file_path); + $pages_in_file = shell_exec($cmd); + $page = new \Imagick(); + $page->readImageBlob($pages_in_file); + $img->addImage($page); + } + + return $img; + } + // otherwise we try to extract the pages using the Imagick API + $resource = $stream->detach(); + fseek($resource, 0); + $img->readImageFile($resource); + return $img; + } + } diff --git a/src/ResourceStorage/Flavour/Machine/DefaultMachines/ExtractPages.php b/src/ResourceStorage/Flavour/Machine/DefaultMachines/ExtractPages.php index 83ff5f773c36..d21384c22bf2 100644 --- a/src/ResourceStorage/Flavour/Machine/DefaultMachines/ExtractPages.php +++ b/src/ResourceStorage/Flavour/Machine/DefaultMachines/ExtractPages.php @@ -23,7 +23,6 @@ use ILIAS\Filesystem\Stream\Streams; use ILIAS\ResourceStorage\Flavour\Definition\FlavourDefinition; use ILIAS\ResourceStorage\Flavour\Definition\PagesToExtract; -use ILIAS\ResourceStorage\Flavour\Engine\ImagickEngine; use ILIAS\ResourceStorage\Flavour\Machine\FlavourMachine; use ILIAS\ResourceStorage\Flavour\Machine\Result; use ILIAS\ResourceStorage\Information\FileInformation; @@ -31,7 +30,6 @@ use ILIAS\ResourceStorage\Flavour\Machine\DefaultMachines\Extract\General; use ILIAS\ResourceStorage\Flavour\Machine\DefaultMachines\Extract\PDF; use ILIAS\ResourceStorage\Flavour\Machine\DefaultMachines\Extract\Video; -use ILIAS\ResourceStorage\Flavour\Engine\FFMpegEngine; use ILIAS\ResourceStorage\Flavour\Engine\ImagickEngineWithOptionalFFMpeg; /** @@ -92,7 +90,7 @@ public function processStream( case ($mime_type === 'image/svg+xml' || $mime_type === 'image/svg'): $extractor = new SVG(); break; - case (strpos($mime_type, 'video') !== false): + case (str_contains($mime_type, 'video')): $extractor = new Video(); break; case ($mime_type === 'application/pdf'): @@ -113,7 +111,7 @@ public function processStream( // Read source image try { $img = $extractor->readImage($img, $stream, $for_definition); - } catch (\ImagickException $e) { + } catch (\ImagickException) { // due to possible security risks, gs disabled access to files, see e.g. https://en.linuxportal.info/tutorials/troubleshooting/how-to-fix-errors-from-imagemagick-imagick-conversion-system-security-policy return; } diff --git a/templates/default/070-components/UI-framework/Input/_ui-component_tag.scss b/templates/default/070-components/UI-framework/Input/_ui-component_tag.scss index bc15b0a1a252..1a8c8d0c270b 100644 --- a/templates/default/070-components/UI-framework/Input/_ui-component_tag.scss +++ b/templates/default/070-components/UI-framework/Input/_ui-component_tag.scss @@ -28,6 +28,7 @@ $il-input-tag-color-disabled: #EEEEEE; border: none; box-shadow: none; outline: none; + height: auto; line-height: $il-line-height-base; font-weight: $il-font-weight-bold !important; } diff --git a/templates/default/delos.css b/templates/default/delos.css index 81a96e8abfde..354d61f2fab2 100644 --- a/templates/default/delos.css +++ b/templates/default/delos.css @@ -3996,6 +3996,7 @@ hr.il-divider-with-label { border: none; box-shadow: none; outline: none; + height: auto; line-height: 1.428571429; font-weight: 600 !important; }