19declare(strict_types=1);
59 private readonly UIFactory $ui_factory,
60 private readonly UIRenderer $ui_renderer,
65 private readonly ContentStyle $content_style,
66 private readonly HTTPServices
$http,
73 $this->ref_id = $this->
object->getRefId();
74 $this->main_settings = $this->
object->getMainSettings();
75 $this->data_factory =
new DataFactory();
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);
109 $this->tpl->setPermanentLink($this->
object->getType(), $this->ref_id);
119 $this->tpl->setContent(
120 $this->ui_renderer->render(
121 $this->testCanBeStarted() ? $this->handleRenderLauncher($elements) : $elements
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');
143 if ($test_behaviour_settings->getProcessingTimeEnabled() && !$this->isUserOutOfProcessingTime()) {
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())))
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'),
294 $class = $this->
object->isFixedTest()
295 ? \ilTestPlayerFixedQuestionSetGUI::class
296 : \ilTestPlayerRandomQuestionSetGUI::class;
297 $url = $this->
ctrl->getLinkTargetByClass(
298 [\ilRepositoryGUI::class, \ilObjTestGUI::class, $class],
301 return $this->data_factory->link($this->
lng->txt(
'tst_resume_test'), $this->data_factory->uri(ILIAS_HTTP_PATH .
'/' .
$url));
308 $this->ui_factory->input()->field()->group($this->getModalLauncherInputs()),
309 function (
Result $result) {
313 )->withModalSubmitLabel($this->
lng->txt(
'continue'));
315 $request = $this->
http->request();
316 $key =
'launcher_id';
317 if (array_key_exists($key, $request->getQueryParams())
318 && $request->getQueryParams()[$key] ===
'exam_modal') {
319 $launcher = $launcher->withRequest($request);
326 $uri = $this->data_factory->uri($this->
http->request()->getUri()->__toString())->withParameter(
'launcher_id',
'exam_modal');
327 return $this->data_factory->link($this->
lng->txt(
'tst_exam_start'), $uri);
332 if ($this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()) {
333 $modal_inputs[
'exam_conditions'] = $this->ui_factory->input()->field()->checkbox(
334 $this->
lng->txt(
'tst_exam_conditions'),
335 $this->lng->txt(
'tst_exam_conditions_label')
336 )->withRequired(
true);
339 if ($this->main_settings->getAccessSettings()->getPasswordEnabled()) {
340 $modal_inputs[
'exam_password'] = $this->ui_factory->input()->field()->password(
341 $this->
lng->txt(
'tst_exam_password'),
342 $this->lng->txt(
'tst_exam_password_label')
343 )->withRevelation(
true)
345 ->withAdditionalTransformation(
346 $this->
refinery->custom()->transformation(
347 static function (
Password $value):
string {
354 if ($this->
user->isAnonymous()) {
355 $access_code_input = $this->ui_factory->input()->field()->text(
356 $this->
lng->txt(
'tst_exam_access_code'),
357 $this->lng->txt(
'tst_exam_access_code_label')
360 $access_code_from_session = $this->test_session->getAccessCodeFromSession();
361 if ($access_code_from_session) {
362 $access_code_input = $access_code_input->withValue($access_code_from_session);
365 $modal_inputs[
'exam_access_code'] = $access_code_input;
368 if ($this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
369 && $this->test_passes_selector->getLastFinishedPass() >= 0) {
370 $modal_inputs[
'exam_use_previous_answers'] = $this->ui_factory->input()->field()->checkbox(
371 $this->
lng->txt(
'tst_exam_use_previous_answers'),
372 $this->lng->txt(
'tst_exam_use_previous_answers_label')
376 return $modal_inputs ?? [];
381 $exam_conditions_enabled = $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled();
382 $password_enabled = $this->main_settings->getAccessSettings()->getPasswordEnabled();
384 if ($exam_conditions_enabled && $password_enabled) {
385 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_conditions_and_password');
386 } elseif ($exam_conditions_enabled) {
387 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_conditions');
388 } elseif ($password_enabled) {
389 $modal_message_box_message = $this->
lng->txt(
'tst_exam_modal_message_password');
392 return isset($modal_message_box_message) ? $this->ui_factory->messageBox()->info($modal_message_box_message) :
null;
397 $class = $this->
object->isFixedTest()
398 ? \ilTestPlayerFixedQuestionSetGUI::class
399 : \ilTestPlayerRandomQuestionSetGUI::class;
400 $url = $this->
ctrl->getLinkTargetByClass(
401 [\ilRepositoryGUI::class, \ilObjTestGUI::class, $class],
404 return $this->data_factory->link($this->
lng->txt(
'tst_exam_start'), $this->data_factory->uri(ILIAS_HTTP_PATH .
'/' .
$url));
409 if ($result->
isOK()) {
410 $conditions_met =
true;
412 $access_settings_password = $this->main_settings->getAccessSettings()->getPassword();
413 $anonymous = $this->
user->isAnonymous();
414 foreach ($result->
value() as $key => $value) {
417 case 'exam_conditions':
418 $exam_conditions_value = (bool) $value;
419 if (!$exam_conditions_value) {
420 $conditions_met =
false;
421 $message .= $this->
lng->txt(
'tst_exam_conditions_not_checked_message') .
'<br>';
424 case 'exam_password':
426 $exam_password_valid = ($password === $access_settings_password);
427 if (!$exam_password_valid) {
428 $conditions_met =
false;
429 $message .= $this->
lng->txt(
'tst_exam_password_invalid_message') .
'<br>';
430 if ($this->
object->getTestLogger()->isLoggingEnabled()
431 && !$this->
object->getAnonymity()) {
432 $logger = $this->
object->getTestLogger();
433 $logger->logParticipantInteraction(
434 $logger->getInteractionFactory()->buildParticipantInteraction(
437 $this->
user->getId(),
439 TestParticipantInteractionTypes::WRONG_TEST_PASSWORD_PROVIDED,
445 $this->password_checker->setUserEnteredPassword($password);
447 case 'exam_access_code':
448 if ($anonymous && !empty($value)) {
449 $this->test_session->setAccessCodeToSession($value);
451 $this->test_session->unsetAccessCodeInSession();
454 case 'exam_use_previous_answers':
455 $exam_use_previous_answers_value = (string) (
int) $value;
460 if ($message !==
'') {
464 if (empty($result->
value())) {
465 $this->tpl->setOnScreenMessage(
467 $this->
lng->txt(
'tst_exam_required_fields_not_filled_message'),
470 } elseif ($conditions_met) {
473 $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
475 $this->
user->setPref(
'tst_use_previous_answers', $exam_use_previous_answers_value ??
'0');
476 $this->
user->update();
479 if (isset($password) && $password === $access_settings_password) {
483 $this->test_session->setPasswordChecked(
false);
486 $this->
ctrl->redirectByClass(
492 $this->tpl->setOnScreenMessage(
494 $this->
lng->txt(
'tst_exam_required_fields_not_filled_message'),
502 if ($this->
object->getOfflineStatus()
503 || !$this->object->isComplete($this->object->getQuestionSetConfig())) {
512 $test_behaviour_settings = $this->
object->getMainSettings()->getTestBehaviourSettings();
513 if (!$test_behaviour_settings->getProcessingTimeEnabled()
514 || $test_behaviour_settings->getResetProcessingTime()) {
518 $active_id = $this->test_passes_selector->getActiveId();
519 $last_started_pass = $this->test_session->getLastStartedPass();
520 return $last_started_pass !==
null
521 && $this->
object->isMaxProcessingTimeReached(
522 $this->
object->getStartingTimeOfUser($active_id, $last_started_pass),
529 if ($this->main_settings->getTestBehaviourSettings()->getBlockAfterPassedEnabled()) {
530 return $this->test_passes_selector->getLastFinishedPass() >= 0
531 && $this->test_passes_selector->hasTestPassedOnce($this->test_session->getActiveId());
539 $nr_of_tries = $this->
object->getNrOfTries();
541 return $nr_of_tries === 0 || (count($this->test_passes_selector->getExistingPasses()) <= $nr_of_tries && count($this->test_passes_selector->getClosedPasses()) < $nr_of_tries);
546 return (count($this->test_passes_selector->getExistingPasses()) - count($this->test_passes_selector->getClosedPasses())) === 1;
552 $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()
553 || $this->main_settings->getAccessSettings()->getPasswordEnabled()
554 || $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
555 && $this->test_passes_selector->getLastFinishedPass() >= 0
556 || $this->user->isAnonymous()
562 $message = $this->
lng->txt(
'tst_skl_level_thresholds_missing');
568 $link = $this->ui_factory->link()->standard(
569 $this->
lng->txt(
'tst_skl_level_thresholds_link'),
573 return $this->ui_factory->messageBox()->failure($message)->withLinks([$link]);
578 if (!$this->
object->isSkillServiceEnabled()) {
582 $questionContainerId = $this->
object->getId();
584 $assignmentList = new \ilAssQuestionSkillAssignmentList($this->
database);
585 $assignmentList->setParentObjId($questionContainerId);
586 $assignmentList->loadFromDb();
588 foreach ($assignmentList->getUniqueAssignedSkills() as
$data) {
589 foreach (
$data[
'skill']->getLevelData() as $level) {
590 $threshold = new \ilTestSkillLevelThreshold($this->
database);
591 $threshold->setTestId($this->
object->getTestId());
592 $threshold->setSkillBaseId(
$data[
'skill_base_id']);
593 $threshold->setSkillTrefId(
$data[
'skill_tref_id']);
594 $threshold->setSkillLevelId($level[
'id']);
596 if (!$threshold->dbRecordExists()) {
607 $target = array_merge([
'ilRepositoryGUI',
'ilObjTestGUI'], [
'ilTestSkillAdministrationGUI',
'ilTestSkillLevelThresholdsGUI']);
608 return $this->
ctrl->getLinkTargetByClass($target, $cmd);
Builds a Color from either hex- or rgb values.
A Link is the often used combination of a label and an URL.
A password is used as part of credentials for authentication.
areSkillLevelThresholdsMissing()
handleRenderIntroduction(array $elements)
readonly DataFactory $data_factory
getModalLauncherMessageBox()
__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)
handleRenderMessageBox(array $elements)
handleRenderLauncher(array $elements)
blockUserAfterHavingPassed()
readonly ilTestSession $test_session
evaluateLauncherModalForm(Result $result)
ilTestPasswordChecker $password_checker
getSkillLevelThresholdsMissingInfo()
isUserOutOfProcessingTime()
readonly MainSettings $main_settings
buildLinkTarget(?string $cmd=null)
readonly ilTestPassesSelector $test_passes_selector
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
class ilRbacSystem system function like checkAccess, addActiveRole ... Supporting system functions ar...
static set(string $a_var, $a_val)
Set a value.
const CMD_SHOW_SKILL_THRESHOLDS
A result encapsulates a value or an error and simplifies the handling of those.
isOK()
Get to know if the result is ok.
value()
Get the encapsulated value.
const MESSAGE_TYPE_FAILURE
withButtonLabel(string $label, bool $launchable=true)
Labels the button that launches the process; if the process is not launchable for the user,...
withInputs(Group $fields, \Closure $evaluation, ?MessageBox\MessageBox $instruction=null)
If the Launcher is configured with Inputs, an Roundtrip Modal is shown with these Inputs.
An entity that renders components to a string output.
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static http()
Fetches the global http state from ILIAS.
TestParticipantInteractionTypes