19 declare(strict_types=1);
65 private readonly ContentStyle $content_style,
73 $this->ref_id = $this->
object->getRefId();
74 $this->main_settings = $this->
object->getMainSettings();
77 $this->test_session = (new \ilTestSessionFactory($this->
object, $this->
database, $this->
user))->getSession();
79 $this->test_passes_selector = new \ilTestPassesSelector($this->
database, $this->
object);
80 $this->test_passes_selector->setActiveId($this->test_session->getActiveId());
81 $this->test_passes_selector->setLastFinishedPass($this->test_session->getLastFinishedPass());
82 $this->password_checker = new \ilTestPasswordChecker($this->rbac_system, $this->
user, $this->
object, $this->
lng);
87 if ($this->
access->checkAccess(
'read',
'', $this->ref_id)) {
88 $this->{$this->
ctrl->getCmd(self::DEFAULT_CMD)}();
94 if (!$this->
object->getMainSettings()->getAdditionalSettings()->getHideInfoTab()) {
95 $this->
ctrl->redirectByClass([\ilRepositoryGUI::class, \ilObjTestGUI::class, \ilInfoScreenGUI::class]);
98 $this->tpl->setOnScreenMessage(
'failure', sprintf(
99 $this->
lng->txt(
'msg_no_perm_read_item'),
100 $this->
object->getTitle()
103 $this->
ctrl->redirectByClass(\ilRepositoryGUI::class);
119 $this->tpl->setContent(
120 $this->ui_renderer->render(
128 $message_box_message =
'';
129 $message_box_message_elements = [];
131 $exam_conditions_enabled = $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled();
132 $password_enabled = $this->main_settings->getAccessSettings()->getPasswordEnabled();
133 $test_behaviour_settings = $this->main_settings->getTestBehaviourSettings();
135 if ($exam_conditions_enabled && $password_enabled) {
136 $message_box_message_elements[] = $this->
lng->txt(
'tst_launcher_status_message_conditions_and_password');
137 } elseif ($exam_conditions_enabled) {
138 $message_box_message_elements[] = $this->
lng->txt(
'tst_launcher_status_message_conditions');
139 } elseif ($password_enabled) {
140 $message_box_message_elements[] = $this->
lng->txt(
'tst_launcher_status_message_password');
144 $message_box_message_elements[] = sprintf(
145 $this->
lng->txt(
'tst_time_limit_message'),
146 $test_behaviour_settings->getProcessingTimeAsMinutes()
150 $nr_of_tries = $this->
object->getNrOfTries();
152 if ($nr_of_tries !== 0) {
153 $message_box_message_elements[] = sprintf($this->
lng->txt(
'tst_attempt_limit_message'), $nr_of_tries);
156 if ($this->
object->isStartingTimeEnabled() && !$this->
object->startingTimeReached()) {
157 $message_box_message_elements[] = sprintf(
158 $this->
lng->txt(
'detail_starting_time_not_reached'),
163 if ($this->
object->isEndingTimeEnabled() && !$this->
object->endingTimeReached()) {
164 $message_box_message_elements[] = sprintf(
165 $this->
lng->txt(
'tst_exam_ending_time_message'),
170 foreach ($message_box_message_elements as $message_box_message_element) {
171 $message_box_message .=
' ' . $message_box_message_element;
174 if (!empty($message_box_message)) {
175 $elements[] = $this->ui_factory->messageBox()->info($message_box_message);
183 $introduction = $this->
object->getIntroduction();
186 $this->main_settings->getIntroductionSettings()->getIntroductionEnabled() &&
187 !empty($introduction)
189 $this->content_style->gui()->addCss($this->tpl, $this->ref_id);
190 $elements[] = $this->ui_factory->panel()->standard(
191 $this->
lng->txt(
'tst_introduction'),
192 $this->ui_factory->legacy()->content($introduction),
207 $launcher_factory = $this->ui_factory->launcher();
209 if ($this->
object->isStartingTimeEnabled() && !$this->
object->startingTimeReached()) {
210 return $launcher_factory
211 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
212 ->withButtonLabel(sprintf(
213 $this->
lng->txt(
'detail_starting_time_not_reached'),
219 if ($this->
object->isEndingTimeEnabled() && $this->
object->endingTimeReached()) {
220 return $launcher_factory
221 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
222 ->withButtonLabel(sprintf(
223 $this->
lng->txt(
'detail_ending_time_reached'),
230 return $launcher_factory
231 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
232 ->withButtonLabel($this->
lng->txt(
'tst_out_of_time_message'),
false)
236 $participant_access = $this->test_access->isParticipantAllowed(
241 if ($participant_access === ParticipantAccess::NOT_INVITED) {
242 return $launcher_factory
243 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
244 ->withButtonLabel($this->
lng->txt(
'tst_exam_not_assigned_participant_disclaimer'),
false)
248 if ($participant_access !== ParticipantAccess::ALLOWED) {
249 return $launcher_factory
250 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
251 ->withButtonLabel($participant_access->getAccessForbiddenMessage($this->lng),
false)
256 return $launcher_factory
257 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
258 ->withButtonLabel($this->
lng->txt(
'tst_launcher_button_label_passes_limit_reached'),
false);
262 return $launcher_factory
263 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
264 ->withButtonLabel($this->
lng->txt(
'tst_already_passed_cannot_retake'),
false)
268 $next_pass_allowed_timestamp = 0;
269 if (!$this->
object->isNextPassAllowed($this->test_passes_selector, $next_pass_allowed_timestamp)) {
270 return $launcher_factory
271 ->inline($this->data_factory->link(
'', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
274 $this->
lng->txt(
'wait_for_next_pass_hint_msg'),
298 return $this->data_factory->link($this->
lng->txt(
'tst_resume_test'), $this->data_factory->uri(ILIAS_HTTP_PATH .
'/' .
$url));
306 function (
Result $result) {
310 )->withModalSubmitLabel($this->
lng->txt(
'continue'));
312 $request = $this->
http->request();
313 $key =
'launcher_id';
314 if (array_key_exists($key, $request->getQueryParams())
315 && $request->getQueryParams()[$key] ===
'exam_modal') {
316 $launcher = $launcher->withRequest($request);
323 $uri = $this->data_factory->uri($this->
http->request()->getUri()->__toString())->withParameter(
'launcher_id',
'exam_modal');
324 return $this->data_factory->link($this->
lng->txt(
'tst_exam_start'), $uri);
329 if ($this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()) {
330 $modal_inputs[
'exam_conditions'] = $this->ui_factory->input()->field()->checkbox(
331 $this->
lng->txt(
'tst_exam_conditions'),
332 $this->
lng->txt(
'tst_exam_conditions_label')
333 )->withRequired(
true);
336 if ($this->main_settings->getAccessSettings()->getPasswordEnabled()) {
337 $modal_inputs[
'exam_password'] = $this->ui_factory->input()->field()->password(
338 $this->
lng->txt(
'tst_exam_password'),
339 $this->
lng->txt(
'tst_exam_password_label')
340 )->withRevelation(
true)
342 ->withAdditionalTransformation(
343 $this->
refinery->custom()->transformation(
344 static function (
Password $value):
string {
351 if ($this->
user->isAnonymous()) {
352 $access_code_input = $this->ui_factory->input()->field()->text(
353 $this->
lng->txt(
'tst_exam_access_code'),
354 $this->
lng->txt(
'tst_exam_access_code_label')
357 $access_code_from_session = $this->test_session->getAccessCodeFromSession();
358 if ($access_code_from_session) {
359 $access_code_input = $access_code_input->withValue($access_code_from_session);
362 $modal_inputs[
'exam_access_code'] = $access_code_input;
365 if ($this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
366 && $this->test_passes_selector->getLastFinishedPass() >= 0) {
367 $modal_inputs[
'exam_use_previous_answers'] = $this->ui_factory->input()->field()->checkbox(
368 $this->
lng->txt(
'tst_exam_use_previous_answers'),
369 $this->
lng->txt(
'tst_exam_use_previous_answers_label')
373 return $modal_inputs ?? [];
378 $exam_conditions_enabled = $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled();
379 $password_enabled = $this->main_settings->getAccessSettings()->getPasswordEnabled();
381 if ($exam_conditions_enabled && $password_enabled) {
382 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_conditions_and_password');
383 } elseif ($exam_conditions_enabled) {
384 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_conditions');
385 } elseif ($password_enabled) {
386 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_password');
389 return isset($modal_message_box_message) ? $this->ui_factory->messageBox()->info($modal_message_box_message) :
null;
398 return $this->data_factory->link($this->
lng->txt(
'tst_exam_start'), $this->data_factory->uri(ILIAS_HTTP_PATH .
'/' .
$url));
403 if ($result->
isOK()) {
404 $conditions_met =
true;
406 $access_settings_password = $this->main_settings->getAccessSettings()->getPassword();
407 $anonymous = $this->
user->isAnonymous();
408 foreach ($result->
value() as $key => $value) {
411 case 'exam_conditions':
412 $exam_conditions_value = (bool) $value;
413 if (!$exam_conditions_value) {
414 $conditions_met =
false;
415 $message .= $this->
lng->txt(
'tst_exam_conditions_not_checked_message') .
'<br>';
418 case 'exam_password':
420 $exam_password_valid = ($password === $access_settings_password);
421 if (!$exam_password_valid) {
422 $conditions_met =
false;
423 $message .= $this->
lng->txt(
'tst_exam_password_invalid_message') .
'<br>';
424 if ($this->
object->getTestLogger()->isLoggingEnabled()
425 && !$this->
object->getAnonymity()) {
426 $logger = $this->
object->getTestLogger();
427 $logger->logParticipantInteraction(
428 $logger->getInteractionFactory()->buildParticipantInteraction(
431 $this->
user->getId(),
433 TestParticipantInteractionTypes::WRONG_TEST_PASSWORD_PROVIDED,
439 $this->password_checker->setUserEnteredPassword($password);
441 case 'exam_access_code':
442 if ($anonymous && !empty($value)) {
443 $this->test_session->setAccessCodeToSession($value);
445 $this->test_session->unsetAccessCodeInSession();
448 case 'exam_use_previous_answers':
449 $exam_use_previous_answers_value = (string) (
int) $value;
458 if (empty($result->
value())) {
459 $this->tpl->setOnScreenMessage(
461 $this->
lng->txt(
'tst_exam_required_fields_not_filled_message'),
464 } elseif ($conditions_met) {
467 $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
469 $this->
user->setPref(
'tst_use_previous_answers', $exam_use_previous_answers_value ??
'0');
470 $this->
user->update();
473 if (isset($password) && $password === $access_settings_password) {
477 $this->test_session->setPasswordChecked(
false);
480 $this->
ctrl->redirectByClass(
486 $this->tpl->setOnScreenMessage(
488 $this->
lng->txt(
'tst_exam_required_fields_not_filled_message'),
496 if ($this->
object->getOfflineStatus()
497 || !$this->
object->isComplete($this->
object->getQuestionSetConfig())) {
506 $test_behaviour_settings = $this->
object->getMainSettings()->getTestBehaviourSettings();
507 if (!$test_behaviour_settings->getProcessingTimeEnabled()
508 || $test_behaviour_settings->getResetProcessingTime()) {
512 $active_id = $this->test_passes_selector->getActiveId();
513 $last_started_pass = $this->test_session->getLastStartedPass();
514 return $last_started_pass !==
null 515 && $this->
object->isMaxProcessingTimeReached(
516 $this->
object->getStartingTimeOfUser($active_id, $last_started_pass),
523 if ($this->main_settings->getTestBehaviourSettings()->getBlockAfterPassedEnabled()) {
524 return $this->test_passes_selector->getLastFinishedPass() >= 0
525 && $this->test_passes_selector->hasTestPassedOnce($this->test_session->getActiveId());
533 $nr_of_tries = $this->
object->getNrOfTries();
535 return $nr_of_tries === 0 || (count($this->test_passes_selector->getExistingPasses()) <= $nr_of_tries && count($this->test_passes_selector->getClosedPasses()) < $nr_of_tries);
540 return (count($this->test_passes_selector->getExistingPasses()) - count($this->test_passes_selector->getClosedPasses())) === 1;
546 $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()
547 || $this->main_settings->getAccessSettings()->getPasswordEnabled()
548 || $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
549 && $this->test_passes_selector->getLastFinishedPass() >= 0
550 || $this->
user->isAnonymous()
556 $message = $this->
lng->txt(
'tst_skl_level_thresholds_missing');
562 $link = $this->ui_factory->link()->standard(
563 $this->
lng->txt(
'tst_skl_level_thresholds_link'),
567 return $this->ui_factory->messageBox()->failure(
$message)->withLinks([$link]);
572 if (!$this->
object->isSkillServiceEnabled()) {
576 $questionContainerId = $this->
object->getId();
578 $assignmentList = new \ilAssQuestionSkillAssignmentList($this->
database);
579 $assignmentList->setParentObjId($questionContainerId);
580 $assignmentList->loadFromDb();
582 foreach ($assignmentList->getUniqueAssignedSkills() as
$data) {
583 foreach (
$data[
'skill']->getLevelData() as $level) {
584 $threshold = new \ilTestSkillLevelThreshold($this->
database);
585 $threshold->setTestId($this->
object->getTestId());
586 $threshold->setSkillBaseId(
$data[
'skill_base_id']);
587 $threshold->setSkillTrefId(
$data[
'skill_tref_id']);
588 $threshold->setSkillLevelId($level[
'id']);
590 if (!$threshold->dbRecordExists()) {
601 $target = array_merge([
'ilRepositoryGUI',
'ilObjTestGUI'], [
'ilTestSkillAdministrationGUI',
'ilTestSkillLevelThresholdsGUI']);
602 return $this->
ctrl->getLinkTargetByClass($target, $cmd);
isOK()
Get to know if the result is ok.
buildLinkTarget(?string $cmd=null)
handleRenderMessageBox(array $elements)
handleRenderIntroduction(array $elements)
isUserOutOfProcessingTime()
value()
Get the encapsulated value.
blockUserAfterHavingPassed()
areSkillLevelThresholdsMissing()
A password is used as part of credentials for authentication.
ilTestPasswordChecker $password_checker
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
readonly ilTestSession $test_session
static http()
Fetches the global http state from ILIAS.
getModalLauncherMessageBox()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
readonly MainSettings $main_settings
const CMD_SHOW_SKILL_THRESHOLDS
TestParticipantInteractionTypes
handleRenderLauncher(array $elements)
evaluateLauncherModalForm(Result $result)
readonly ilTestPassesSelector $test_passes_selector
getSkillLevelThresholdsMissingInfo()
readonly DataFactory $data_factory
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
const MESSAGE_TYPE_FAILURE
__construct(private readonly \ilObjTest $object, private readonly \ilObjUser $user, private readonly UIFactory $ui_factory, private readonly UIRenderer $ui_renderer, private readonly \ilLanguage $lng, private readonly Refinery $refinery, private readonly \ilCtrlInterface $ctrl, private readonly \ilGlobalTemplateInterface $tpl, private readonly ContentStyle $content_style, private readonly HTTPServices $http, private readonly TabsManager $tabs_manager, private readonly \ilAccessHandler $access, private readonly \ilTestAccess $test_access, private readonly \ilDBInterface $database, private readonly \ilRbacSystem $rbac_system)
static set(string $a_var, $a_val)
Set a value.