19 declare(strict_types=1);
68 protected function buildSubTabs(
string $active_sub_tab =
'man_scoring_by_qst'): void
70 $this->
tabs->addSubTab(
72 $this->
lng->txt(
'tst_man_scoring_by_qst'),
73 $this->
ctrl->getLinkTargetByClass([\ilObjTestGUI::class, TestScoringByQuestionGUI::class],
'showManScoringByQuestionParticipantsTable')
75 $this->
tabs->addSubTab(
77 $this->
lng->txt(
'tst_man_scoring_by_part'),
78 $this->
ctrl->getLinkTargetByClass([\ilObjTestGUI::class, self::class],
'showManScoringParticipantsTable')
80 $this->
tabs->setSubTabActive($active_sub_tab);
85 if (!$this->testrequest->isset(
'active_id') || $this->testrequest->int(
'active_id') === 0) {
86 $this->tpl->setOnScreenMessage(
'failure',
'no active id given!',
true);
87 $this->
ctrl->redirectByClass([\ilRepositoryGUI::class, \ilObjTestGUI::class, \ilInfoScreenGUI::class]);
90 return $this->testrequest->int(
'active_id');
95 $max_pass = $this->
object->_getMaxPass($active_id);
98 if ($this->testrequest->isset(
'pass')) {
99 $pass_from_request = $this->testrequest->int(
'pass');
100 if ($pass_from_request >= 0
101 && $pass_from_request <= $max_pass
103 return $pass_from_request;
111 return $this->
object->_getResultPass($active_id);
120 && !$this->
getTestAccess()->checkScoreParticipantsAccessAnon()
122 \ilObjTestGUI::accessViolationRedirect();
125 if (!$this->
object->getGlobalSettings()->isManualScoringEnabled()) {
127 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"manscoring_not_allowed"),
true);
128 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
145 return 'man_scoring';
151 $this->tpl->setContent($table->getHTML());
157 $table->resetOffset();
158 $table->writeFilterToSession();
166 $table->resetOffset();
167 $table->resetFilter();
176 if (!$this->
getTestAccess()->checkScoreParticipantsAccessForActiveId($active_id, $this->
object->getTestId())) {
177 \ilObjTestGUI::accessViolationRedirect();
186 $user_id = $this->
object->_getUserIdFromActiveId($active_id);
187 $user_fullname = $this->
object->userLookupFullName(
$user_id,
false,
true);
193 $table_title = sprintf($this->
lng->txt(
'tst_pass_overview_for_participant'), $participant_name);
194 $table->setTitle($table_title);
196 $passOverviewData = $this->service->getPassOverviewData($active_id);
197 $table->setData($passOverviewData[
'passes']);
199 $content_html .= $table->getHTML() .
'<br />';
201 if ($form ===
null) {
206 $content_html .= $form->getHTML();
208 $this->tpl->setContent($content_html);
215 if (!$this->
getTestAccess()->checkScoreParticipantsAccessForActiveId($active_id, $this->
object->getTestId())) {
216 \ilObjTestGUI::accessViolationRedirect();
224 $form->setValuesByPost();
226 if (!$form->checkInput()) {
227 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_save_manscoring_failed'), $attempt + 1));
232 $max_points_by_question_id = [];
233 $max_points_exceeded =
false;
234 foreach (array_keys($question_gui_list) as $question_id) {
235 $reached_points = $form->getItemByPostVar(
"question__{$question_id}__points")->getValue();
236 $max_points = $this->questionrepository->getForQuestionId($question_id)->getAvailablePoints();
238 if ($reached_points > $max_points) {
239 $max_points_exceeded =
true;
241 $form->getItemByPostVar(
"question__{$question_id}__points")->setAlert(sprintf(
242 $this->
lng->txt(
'tst_manscoring_maxpoints_exceeded_input_alert'),
247 $max_points_by_question_id[$question_id] = $max_points;
250 if ($max_points_exceeded) {
251 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_save_manscoring_failed'), $attempt + 1));
256 foreach (array_keys($question_gui_list) as $question_id) {
258 $reached_points = $this->
refinery->byTrying([
259 $this->
refinery->kindlyTo()->float(),
260 $this->
refinery->always($old_points)
261 ])->
transform($form->getItemByPostVar(
"question__{$question_id}__points")?->getValue());
263 $finalized = (bool) $form->getItemByPostVar(
"{$question_id}__evaluated")?->getChecked();
266 if ($reached_points !== $old_points) {
267 \assQuestion::_setReachedPoints(
271 $max_points_by_question_id[$question_id],
278 (
string) $form->getItemByPostVar(
"question__{$question_id}__feedback")->getValue(),
283 $this->
object->saveManualFeedback(
291 if ($this->
logger->isLoggingEnabled()) {
292 $this->
logger->getInteractionFactory()->buildScoringInteraction(
295 $this->
user->getId(),
297 TestScoringInteractionTypes::QUESTION_GRADED,
302 ->getAdditionalInformationGenerator()->getTrueFalseTagForBool(
true)
307 $notification_data[$question_id] = [
308 'points' => $reached_points,
'feedback' => $feedback_text
317 $manScoringDone = $form->getItemByPostVar(
"manscoring_done")->getChecked();
320 $manScoringNotify = $form->getItemByPostVar(
"manscoring_notify")->getChecked();
321 if ($manScoringNotify) {
322 $notification = new \ilTestManScoringParticipantNotification(
323 $this->
object->_getUserIdFromActiveId($active_id),
324 $this->
object->getRefId()
327 $notification->setAdditionalInformation([
328 'test_title' => $this->
object->getTitle(),
329 'test_pass' => $attempt + 1,
330 'questions_gui_list' => $question_gui_list,
331 'questions_scoring_data' => $notification_data
334 $notification->send();
337 $scorer =
new TestScoring($this->
object, $this->
user, $this->db, $this->test_result_repository);
338 $scorer->setPreserveManualScores(
true);
339 $scorer->recalculateSolution($active_id, $attempt);
341 if (!$this->
object->getAnonymity()
345 $name_real_or_anon = $user_name[
'firstname'] .
' ' . $user_name[
'lastname'];
347 $name_real_or_anon = $this->
lng->txt(
'anonymous');
349 $this->tpl->setOnScreenMessage(
'success', sprintf($this->
lng->txt(
'tst_saved_manscoring_successfully'), $attempt + 1, $name_real_or_anon),
true);
350 if ($redirect ==
true) {
351 $this->
ctrl->redirect($this,
'showManScoringParticipantScreen');
365 if ($participant[
'active_id'] == $this->testrequest->raw(
'active_id')) {
366 $nextIndex = $index + 1;
373 $this->
ctrl->redirect($this,
'showManScoringParticipantScreen');
376 $this->
ctrl->redirectByClass(self::class,
'showManScoringParticipantsTable');
383 $this->
ctrl->redirectByClass(self::class,
'showManScoringParticipantsTable');
388 array $question_gui_list,
391 bool $initValues =
false 393 $this->
ctrl->setParameter($this,
'active_id', $active_id);
394 $this->
ctrl->setParameter($this,
'pass', $pass);
396 $form = new \ilPropertyFormGUI();
397 $form->setFormAction($this->
ctrl->getFormAction($this));
399 $form->setTitle(sprintf($this->
lng->txt(
'manscoring_results_pass'), $pass + 1));
400 $form->setTableWidth(
'100%');
402 foreach ($question_gui_list as $question_id => $question_gui) {
403 $question_header = sprintf(
404 $this->
lng->txt(
'tst_manscoring_question_section_header'),
405 $question_gui->getObject()->getTitleForHTMLOutput()
407 $question_solution = $question_gui->getSolutionOutput($active_id, $pass,
false,
false,
true,
false,
false,
true);
408 $best_solution = $question_gui->getObject()->getSuggestedSolutionOutput();
413 if (isset($feedback[
'finalized_evaluation']) && $feedback[
'finalized_evaluation'] == 1) {
417 $sect = new \ilFormSectionHeaderGUI();
418 $sect->setTitle($question_header .
' [' . $this->
lng->txt(
'question_id_short') .
': ' . $question_gui->getObject()->getId() .
']');
419 $form->addItem($sect);
421 $cust = new \ilCustomInputGUI($this->
lng->txt(
'tst_manscoring_input_question_and_user_solution'));
422 $cust->setHtml($question_solution);
423 $form->addItem($cust);
425 $number_input_gui = new \ilNumberInputGUI(
426 $this->
lng->txt(
'tst_change_points_for_question'),
427 "question__{$question_id}__points" 429 $number_input_gui->allowDecimals(
true);
435 $number_input_gui->setDisabled($disabled);
437 $form->addItem($number_input_gui);
439 $nonedit = new \ilNonEditableValueGUI($this->
lng->txt(
'tst_manscoring_input_max_points_for_question'),
"question__{$question_id}__maxpoints");
441 $nonedit->setValue($this->questionrepository->getForQuestionId($question_id)->getAvailablePoints());
443 $form->addItem($nonedit);
445 $area = new \ilTextAreaInputGUI($this->
lng->txt(
'set_manual_feedback'),
"question__{$question_id}__feedback");
446 $area->setUseRTE(
true);
451 $area->setDisabled($disabled);
453 $form->addItem($area);
455 $check = new \ilCheckboxInputGUI($this->
lng->txt(
'finalized_evaluation'),
"{$question_id}__evaluated");
461 if (strlen(trim($best_solution))) {
462 $cust = new \ilCustomInputGUI($this->
lng->txt(
'tst_show_solution_suggested'));
463 $cust->setHtml($best_solution);
464 $form->addItem($cust);
468 $sect = new \ilFormSectionHeaderGUI();
469 $sect->setTitle($this->
lng->txt(
'tst_participant'));
470 $form->addItem($sect);
472 $check = new \ilCheckboxInputGUI($this->
lng->txt(
'set_manscoring_done'),
'manscoring_done');
478 $check = new \ilCheckboxInputGUI($this->
lng->txt(
'tst_manscoring_user_notification'),
'manscoring_notify');
481 $form->addCommandButton(
'saveManScoringParticipantScreen', $this->
lng->txt(
'save'));
482 $form->addCommandButton(
'saveReturnManScoringParticipantScreen', $this->
lng->txt(
'save_return'));
483 $form->addCommandButton(
'saveNextManScoringParticipantScreen', $this->
lng->txt(
'save_and_next'));
490 $test_result_data = $this->
object->getTestResult($active_id, $pass);
491 $man_scoring_question_gui_list = [];
493 foreach ($test_result_data as $question_data) {
494 if (!isset($question_data[
'qid'])) {
498 if (!isset($question_data[
'type'])) {
502 $man_scoring_question_gui_list[ $question_data[
'qid'] ] = $this->
object 503 ->createQuestionGUI(
'', $question_data[
'qid']);
505 return $man_scoring_question_gui_list;
512 $this->
object->getAnonOnlyParticipantIds()
516 $participant_list = new \ilTestParticipantList($this->
object, $this->
user, $this->
lng, $this->db);
517 $participant_list->initializeFromDbRows(
518 $this->
object->getTestParticipantsForManualScoring(
519 $table->getFilterItemByPostVar(
'participant_status')->getValue()
524 $participant_list->getAccessFilteredList(
525 $this->participant_access_filter->getScoreParticipantsUserFilter($this->ref_id)
526 )->getScoringTableRows()
538 $anon_only_usr_ids = $this->
object->getAnonOnlyParticipantIds();
539 $user_id = $this->
object->_getUserIdFromActiveId($active_id);
540 if ($name !==
null && !in_array(
$user_id, $anon_only_usr_ids)) {
549 return \ilObjTest::buildExamId($active_id, $pass, $this->
object->getId());
const PART_FILTER_MANSCORING_NONE
const PART_FILTER_MANSCORING_DONE
fetchPassParameter(int $active_id)
buildManScoringParticipantsTable(bool $with_data=false)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
static _lookupName(int $a_user_id)
lookup user name
saveReturnManScoringParticipantScreen()
TestScoringInteractionTypes
static isManScoringDone(int $active_id)
buildManScoringParticipantForm(array $question_gui_list, int $active_id, int $pass, bool $initValues=false)
saveManScoringParticipantScreen(bool $redirect=true)
Base Exception for all Exceptions relating to Modules/Test.
getManScoringQuestionGuiList(int $active_id, int $pass)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
getUserNamePresentation(int $active_id, int|string $pass, ?string $name=null)
saveNextManScoringParticipantScreen()
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
resetManScoringParticipantsFilter()
static setManScoringDone(int $activeId, bool $manScoringDone)
static _getReachedPoints(int $active_id, int $question_id, int $pass)
ilTestAccess $test_access
showManScoringParticipantScreen(?\ilPropertyFormGUI $form=null)
getUserExamId(int $active_id, string $pass)
const TAB_ID_MANUAL_SCORING
executeCommand()
execute command
__construct(\ilObjTest $object)
ilTestParticipantData $participantData
__construct(Container $dic, ilPlugin $plugin)
static _getUsedHTMLTagsAsString(string $module='')
static _getParticipantId(int $active_id)
Get user id for active id.
showManScoringParticipantsTable()
buildSubTabs(string $active_sub_tab='man_scoring_by_qst')
Service GUI class for tests.
const PART_FILTER_ALL_USERS
setTestAccess($test_access)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
applyManScoringParticipantsFilter()