ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilExerciseManagementGUI.php
Go to the documentation of this file.
1<?php
2
32
42{
43 public const VIEW_ASSIGNMENT = 1;
44 public const VIEW_PARTICIPANT = 2;
45 public const VIEW_GRADES = 3;
46
47 public const FEEDBACK_ONLY_SUBMISSION = "submission_only";
48 public const FEEDBACK_FULL_SUBMISSION = "submission_feedback";
49
50 public const GRADE_NOT_GRADED = "notgraded";
51 public const GRADE_PASSED = "passed";
52 public const GRADE_FAILED = "failed";
53 protected ZipAdapter $zip;
55 protected \ILIAS\Exercise\InternalDomainService $domain;
56 protected \ILIAS\Exercise\Notification\NotificationManager $notification;
59 protected \ILIAS\HTTP\Services $http;
60
61 protected ilCtrl $ctrl;
63 protected ilLanguage $lng;
67 protected array $filter = [];
70 protected ?ilExAssignment $assignment = null;
72 protected ilLogger $log;
73 protected ilObjUser $user;
75 protected ?ilDBInterface $db = null;
76 protected int $ass_id = 0;
77 protected int $requested_member_id = 0;
78 protected int $requested_part_id = 0;
79 protected int $requested_ass_id = 0;
80 protected string $requested_idl_id;
81 protected bool $done = false;
83 protected string $requested_comment;
84 protected string $requested_user_login;
85 protected array $selected_participants;
86 protected array $listed_participants;
87 protected array $selected_ass_ids;
88 protected array $listed_ass_ids;
89 protected array $requested_marks; // key might be ass_ids or user_ids!
90 protected array $requested_status; // key might be ass_ids or user_ids!
91 protected array $requested_tutor_notices; // key might be ass_ids or user_ids!
92 protected array $requested_group_members; // "grpt"
94 protected array $requested_files; // "file"
95 protected string $requested_filter_status;
99
106 public function __construct(InternalService $service, ?ilExAssignment $a_ass = null)
107 {
108 global $DIC;
109
110 $this->service = $service;
111 $this->gui = $gui = $service->gui();
112 $this->domain = $domain = $service->domain();
113
114 $this->user = $domain->user();
115 $this->log = $domain->logger()->exc();
116 $this->access = $domain->access();
117 $this->lng = $domain->lng();
118
119 $this->toolbar = $gui->toolbar();
120 $this->ui_factory = $gui->ui()->factory();
121 $this->ui_renderer = $gui->ui()->renderer();
122 $this->ctrl = $gui->ctrl();
123 $this->tabs_gui = $gui->tabs();
124 $this->tpl = $gui->ui()->mainTemplate();
125 $this->http = $gui->http();
126
127 $this->task_factory = $domain->backgroundTasks()->taskFactory();
128 $this->request = $gui->request();
130
131 $this->exercise = $request->getExercise();
132 if ($a_ass !== null) {
133 $this->assignment = $a_ass;
134 $this->ass_id = $this->assignment->getId();
135 }
136 $this->requested_member_id = $request->getMemberId();
137 $this->requested_part_id = $request->getParticipantId();
138 $this->requested_ass_id = $request->getAssId();
139 $this->requested_idl_id = $request->getIdlId();
140 $this->done = $request->getDone();
141 $this->requested_learning_comments = $request->getLearningComments();
142 $this->requested_comment = $request->getComment();
143 $this->requested_user_login = $request->getUserLogin();
144 $this->selected_participants = $request->getSelectedParticipants();
145 $this->listed_participants = $request->getListedParticipants();
146 $this->selected_ass_ids = $request->getSelectedAssignments();
147 $this->listed_ass_ids = $request->getListedAssignments();
148 $this->requested_marks = $request->getMarks();
149 $this->requested_status = $request->getStatus();
150 $this->requested_tutor_notices = $request->getTutorNotices();
151 $this->requested_group_members = $request->getGroupMembers();
152 $this->requested_files = $request->getFiles();
153 $this->requested_filter_status = $request->getFilterStatus();
154 $this->requested_filter_feedback = $request->getFilterFeedback();
155
156 $this->notification = $domain->notification($request->getRefId());
157
158 $this->feedback_gui = $DIC->exercise()->internal()->gui()->getSubmissionFeedbackGUI(
159 $this->exercise,
160 $this->notification
161 );
162
163 $this->ctrl->saveParameter($this, array("vw", "member_id"));
164 if ($this->ass_id > 0) {
165 $this->tutor_feedback_file = $domain->assignment()->tutorFeedbackFile($this->ass_id);
166 }
167 $this->zip = $domain->resources()->zip();
168 $this->ctrl->saveParameter($this, array("part_id"));
169 }
170
175 public function executeCommand(): void
176 {
177 $ilCtrl = $this->ctrl;
179 $ilTabs = $this->tabs_gui;
180
181 $class = $ilCtrl->getNextClass($this);
182 //$cmd = $ilCtrl->getCmd("listPublicSubmissions");
183
184 switch ($class) {
185 // feedback files IRSS
186 case strtolower(ilResourceCollectionGUI::class):
187 $ilTabs->clearTargets();
188 $ilTabs->setBackTarget(
189 $lng->txt("back"),
190 $ilCtrl->getLinkTarget($this, $this->getViewBack())
191 );
192 $this->domain->assignment()->tutorFeedbackFile($this->ass_id)->addObserver();
193 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_fb_tutor_info"));
194 $gui = $this->gui->assignment()->getTutorFeedbackFileResourceCollectionGUI(
195 $this->exercise->getRefId(),
196 $this->assignment->getId(),
197 $this->requested_member_id
198 );
199 $this->ctrl->forwardCommand($gui);
200 break;
201
202 case 'ilrepositorysearchgui':
203 $rep_search = new ilRepositorySearchGUI();
204 $ref_id = $this->exercise->getRefId();
205 $rep_search->addUserAccessFilterCallable(function ($a_user_ids) use ($ref_id) {
206 return $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
207 'edit_submissions_grades',
208 'edit_submissions_grades',
209 $ref_id,
210 $a_user_ids
211 );
212 });
213 $rep_search->setTitle($this->lng->txt("exc_add_participant"));
214 $rep_search->setCallback($this, 'addMembersObject');
215
216 // Set tabs
217 $this->addSubTabs("assignment");
218 $this->ctrl->setReturn($this, 'members');
219
220 $this->ctrl->forwardCommand($rep_search);
221 break;
222
223 case strtolower(ilRepoStandardUploadHandlerGUI::class):
224 $form = $this->getMultiFeedbackForm($this->assignment->getId());
225 $gui = $form->getRepoStandardUploadHandlerGUI("mfzip");
226 $this->ctrl->forwardCommand($gui);
227 break;
228
229 case "ilexsubmissionteamgui":
230 $gui = new ilExSubmissionTeamGUI($this->exercise, $this->initSubmission());
231 $ilCtrl->forwardCommand($gui);
232 break;
233
234 case "ilexsubmissionfilegui":
235 $gui = new ilExSubmissionFileGUI($this->exercise, $this->initSubmission());
236 $ilCtrl->forwardCommand($gui);
237 break;
238
239 case "ilexsubmissiontextgui":
240 $ilCtrl->saveParameter($this, array("part_id"));
241 $gui = new ilExSubmissionTextGUI($this->exercise, $this->initSubmission());
242 $ilCtrl->forwardCommand($gui);
243 break;
244
245 case "ilexpeerreviewgui":
246 $gui = new ilExPeerReviewGUI($this->assignment, $this->initSubmission());
247 $ilCtrl->forwardCommand($gui);
248 break;
249
250 case "ilparticipantsperassignmenttablegui":
252 $this,
253 "members",
254 $this->exercise,
255 $this->assignment->getId(),
256 $this->feedback_gui
257 );
258 $this->ctrl->forwardCommand($table);
259 break;
260
261 case "ilexercisesubmissionfeedbackgui":
262 $this->ctrl->forwardCommand($this->feedback_gui);
263 break;
264
265 default:
266 $cmd = $ilCtrl->getCmd();
267 switch ($cmd) {
268 case 'downloadSubmissions':
269 $cmd = $ilCtrl->getCmd("downloadSubmissions");
270 break;
271 default:
272 $cmd = $ilCtrl->getCmd("listPublicSubmissions");
273 break;
274 }
275 $this->{$cmd . "Object"}();
276 break;
277 }
278 }
279
280 protected function getViewBack(): string
281 {
282 switch ($this->request->getBackView()) {
284 $back_cmd = "showParticipant";
285 break;
286
288 $back_cmd = "showGradesOverview";
289 break;
290
291 default:
292 // case self::VIEW_ASSIGNMENT:
293 $back_cmd = "members";
294 break;
295 }
296 return $back_cmd;
297 }
298
299 protected function initSubmission(): ilExSubmission
300 {
301 $back_cmd = $this->getViewBack();
302 $this->ctrl->setReturn($this, $back_cmd);
303
304 $this->tabs_gui->clearTargets();
305 $this->tabs_gui->setBackTarget(
306 $this->lng->txt("back"),
307 $this->ctrl->getLinkTarget($this, $back_cmd)
308 );
309
310 return new ilExSubmission($this->assignment, $this->requested_member_id, null, true);
311 }
312
313 public function addSubTabs(string $a_activate): void
314 {
315 $ilTabs = $this->tabs_gui;
317 $ilCtrl = $this->ctrl;
318
319 $ass_id = $this->assignment !== null ? $this->assignment->getId() : 0;
320 $part_id = $this->requested_part_id;
321
322 $ilCtrl->setParameter($this, "vw", "");
323 $ilCtrl->setParameter($this, "member_id", "0");
324 $ilCtrl->setParameter($this, "ass_id", "0");
325 $ilCtrl->setParameter($this, "part_id", "0");
326
327 $ilTabs->addSubTab(
328 "assignment",
329 $lng->txt("exc_assignment_view"),
330 $ilCtrl->getLinkTarget($this, "members")
331 );
332 $ilTabs->addSubTab(
333 "participant",
334 $lng->txt("exc_participant_view"),
335 $ilCtrl->getLinkTarget($this, "showParticipant")
336 );
337 $ilTabs->addSubTab(
338 "grades",
339 $lng->txt("exc_grades_overview"),
340 $ilCtrl->getLinkTarget($this, "showGradesOverview")
341 );
342 $ilTabs->activateSubTab($a_activate);
343
344 $ilCtrl->setParameter($this, "ass_id", $ass_id);
345 $ilCtrl->setParameter($this, "part_id", $part_id);
346 }
347
351 public function waitingDownloadObject(): void
352 {
354 $ilCtrl = $this->ctrl;
355
356 $ilCtrl->setParameterByClass("ilExSubmissionFileGUI", "member_id", $this->requested_member_id);
357 $url = $ilCtrl->getLinkTargetByClass(array("ilExerciseHandlerGUI", "ilObjExerciseGUI", "ilExerciseManagementGUI", "ilExSubmissionFileGUI"), "downloadNewReturned");
358 $js_url = $ilCtrl->getLinkTargetByClass(array("ilExerciseHandlerGUI", "ilObjExerciseGUI", "ilExerciseManagementGUI", "ilExSubmissionFileGUI"), "downloadNewReturned", "", "", false);
359 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_wait_for_files") . "<a href='$url'> " . $lng->txt('exc_download_files') . "</a><script>window.location.href ='" . $js_url . "';</script>");
360 $this->membersObject();
361 }
362
367 public function membersObject(): void
368 {
370 $ilToolbar = $this->toolbar;
371 $ilCtrl = $this->ctrl;
373
374 $this->addSubTabs("assignment");
375 $this->gui->permanentLink()->setGradesPermanentLink();
376
377 // assignment selection
378 $ass = ilExAssignment::getInstancesByExercise($this->exercise->getId());
379
380 if ($this->assignment === null && count($ass) > 0) {
381 $this->assignment = current($ass);
382 }
383
384 reset($ass);
385 if (count($ass) > 1) {
386 $options = array();
387 foreach ($ass as $a) {
388 $options[$a->getId()] = $a->getTitle();
389 }
390 $si = new ilSelectInputGUI($this->lng->txt("exc_assignment"), "ass_id");
391 $si->setOptions($options);
392 $si->setValue($this->assignment->getId());
393 $ilToolbar->addStickyItem($si, true);
394 $this->gui->button(
395 $this->lng->txt("select"),
396 "selectAssignment"
397 )->submit()->toToolbar(true);
398
399 $ilToolbar->addSeparator();
400 }
401 // #16165 - if only 1 assignment dropdown is not displayed;
402 elseif ($this->assignment) {
403 $ilCtrl->setParameter($this, "ass_id", $this->assignment->getId());
404 }
405
406 // add member
407 // is only shown if 'edit_submissions_grades' is granted by rbac. positions
408 // access is not sufficient.
409 $has_rbac_access = $GLOBALS['DIC']->access()->checkAccess(
410 'edit_submissions_grades',
411 '',
412 $this->exercise->getRefId()
413 );
414 if ($has_rbac_access) {
416 $this,
417 $ilToolbar,
418 array(
419 'auto_complete_name' => $lng->txt('user'),
420 'submit_name' => $lng->txt('add'),
421 'add_search' => true,
422 'add_from_container' => $this->exercise->getRefId()
423 )
424 );
425 }
426
427 // #16168 - no assignments
428 if ($ass !== []) {
429 if ($has_rbac_access) {
430 $ilToolbar->addSeparator();
431 }
432
433 // we do not want the ilRepositorySearchGUI form action
434 $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
435
436 $ilCtrl->setParameter($this, "ass_id", $this->assignment->getId());
437
438 if ($this->assignment->getType() == ilExAssignment::TYPE_UPLOAD_TEAM) {
439 if (ilExAssignmentTeam::getAdoptableGroups($this->exercise->getRefId())) {
440 $ilToolbar->addButton(
441 $this->lng->txt("exc_adopt_group_teams"),
442 $this->ctrl->getLinkTarget($this, "adoptTeamsFromGroup")
443 );
444
445 $ilToolbar->addSeparator();
446 }
447 } elseif ($this->exercise->hasTutorFeedbackFile()) {
448 if (!$this->assignment->getAssignmentType()->usesTeams()) {
449 // multi-feedback
450 $ilToolbar->addButton(
451 $this->lng->txt("exc_multi_feedback"),
452 $this->ctrl->getLinkTarget($this, "showMultiFeedback")
453 );
454
455 $ilToolbar->addSeparator();
456 }
457 }
458
459 $submission_repository = $this->service->repo()->submission();
460
461 if ($submission_repository->hasSubmissions($this->assignment->getId()) !== 0) {
462 $ass_type = $this->assignment->getType();
463 //todo change addFormButton for addButtonInstance
464 if ($ass_type == ilExAssignment::TYPE_TEXT) {
465 $ilToolbar->addFormButton($lng->txt("exc_list_text_assignment"), "listTextAssignment");
466 }
467 $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
468 }
469 $this->ctrl->setParameter($this, "vw", self::VIEW_ASSIGNMENT);
470
472 $this,
473 "members",
474 $this->exercise,
475 $this->assignment->getId(),
476 $this->feedback_gui
477 );
479 $exc_tab->getHTML() .
480 $this->initIndividualDeadlineModal()
481 );
482 } else {
483 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_no_assignments_available"));
484 }
485
486 $ilCtrl->setParameter($this, "ass_id", "0");
487 }
488
489 public function downloadSelectedObject(): void
490 {
491 if (count($this->selected_participants) > 0) {
492 $this->downloadSubmissionsObject($this->selected_participants);
493 } else {
494 $this->backToCurrentOverview();
495 }
496 }
497 public function downloadSubmissionsObject(?array $selected_participants = null): void
498 {
499 $participant_id = $this->requested_part_id;
500
501 $download_task = new ilDownloadSubmissionsBackgroundTask(
502 (int) $GLOBALS['DIC']->user()->getId(),
503 $this->exercise->getRefId(),
504 $this->exercise->getId(),
505 $this->ass_id,
506 $participant_id,
508 );
509
510 if ($download_task->run()) {
511 $this->tpl->setOnScreenMessage('success', $this->lng->txt('exc_down_files_started_bg'), true);
512 }
513
514 $this->backToCurrentOverview();
515 }
516
517 public function backToCurrentOverview(): void
518 {
519 if ($this->assignment !== null) {
520 $this->ctrl->redirect($this, "members");
521 } else {
522 $this->ctrl->redirect($this, "showParticipant");
523 }
524 }
525
529 public function membersApplyObject(): void
530 {
531 $this->saveStatusAllObject(null, false);
533 $this,
534 "members",
535 $this->exercise,
536 $this->assignment->getId(),
537 $this->feedback_gui
538 );
539 $exc_tab->resetOffset();
540 $exc_tab->writeFilterToSession();
541
542 $this->membersObject();
543 }
544
548 public function membersResetObject(): void
549 {
551 $this,
552 "members",
553 $this->exercise,
554 $this->assignment->getId(),
555 $this->feedback_gui
556 );
557 $exc_tab->resetOffset();
558 $exc_tab->resetFilter();
559
560 $this->membersObject();
561 }
562
563 public function saveGradesObject(): void
564 {
565 $ilCtrl = $this->ctrl;
567
568 foreach ($this->requested_learning_comments as $k => $v) {
569 $marks_obj = new ilLPMarks($this->exercise->getId(), (int) $k);
570 $marks_obj->setComment($v);
571 $marks_obj->update();
572 }
573 foreach ($this->requested_marks as $k => $v) {
574 $marks_obj = new ilLPMarks($this->exercise->getId(), (int) $k);
575 $marks_obj->setMark($v);
576 $marks_obj->update();
577 }
578 $this->tpl->setOnScreenMessage('success', $lng->txt("exc_msg_saved_grades"), true);
579 $ilCtrl->redirect($this, "showGradesOverview");
580 }
581
582
583 // TEXT ASSIGNMENT ?!
584
589 public function listTextAssignmentObject(): void
590 {
591 $this->initFilter();
592 $this->setBackToMembers();
593
595 $button_print = $this->ui_factory->button()->standard($this->lng->txt('print'), "#")
596 ->withOnLoadCode(function ($id) {
597 return "$('#$id').click(function() { window.print(); return false; });";
598 });
599 $this->toolbar->addSeparator();
600 $this->toolbar->addComponent($button_print);
601
602 $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "components/ILIAS/Exercise");
603 $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_list_text_assignment") . ": " . $this->assignment->getTitle());
604
605 $report_html = "";
606 $total_reports = 0;
607
608 $members = ilExSubmission::getAssignmentParticipants($this->exercise->getId(), $this->ass_id);
609 $members_filter = new ilExerciseMembersFilter($this->exercise->getRefId(), $members, $this->user->getId());
610 $members = $members_filter->filterParticipantsByAccess();
611
612 $sm = $this->domain->submission($this->assignment->getId());
613 foreach ($sm->getSubmissionsOfOwners($members) as $sub) {
614 if (trim($sub->getText()) && $this->domain->profile()->exists($sub->getUserId())) {
615 $feedback_data = $this->collectFeedbackDataFromPeer(
616 $sub->getUserId(),
617 $sub->getTimestamp(),
618 $sub->getText()
619 );
620 $submission_data = $this->assignment->getExerciseMemberAssignmentData($sub->getUserId(), $this->filter["status"] ?? "");
621
622 if (is_array($submission_data)) {
623 $data = array_merge($feedback_data, $submission_data);
624 $report_html .= $this->getReportPanel($data);
625 $total_reports++;
626 }
627 }
628 }
629 if ($total_reports == 0) {
630 $mess = $this->ui_factory->messageBox()->info($this->lng->txt("fiter_no_results"));
631 $report_html .= $this->ui_renderer->render($mess);
632 }
633
634 $group_panels_tpl->setVariable('CONTENT', $report_html);
635 $this->tpl->setContent($group_panels_tpl->get());
636 }
637
643 public function compareTextAssignmentsObject(): void
644 {
645 $this->setBackToMembers();
646 $subm = $this->domain->submission($this->assignment->getId());
647
648 $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "components/ILIAS/Exercise");
649 $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_compare_selected_submissions"));
650
651 $report_html = "";
652 //participant ids selected via checkboxes
653 $participants = array_keys($this->getMultiActionUserIds());
654
655 foreach ($participants as $participant_id) {
656 $subs = $subm->getSubmissionsOfUser($participant_id);
657 $ts = "";
658 $text = "";
659 if ($s = $subs->current()) {
660 $ts = $s->getTimestamp();
661 $text = $s->getText();
662 }
663
664 $feedback_data = $this->collectFeedbackDataFromPeer(
665 $participant_id,
666 $ts,
667 $text
668 );
669
670 $submission_data = $this->assignment->getExerciseMemberAssignmentData((int) $participant_id, $this->filter["status"] ?? "");
671
672 if (is_array($submission_data)) {
673 $data = array_merge($feedback_data, $submission_data);
674 $report_html .= $this->getReportPanel($data);
675 }
676 }
677
678 $group_panels_tpl->setVariable('CONTENT', $report_html);
679 $this->tpl->setContent($group_panels_tpl->get());
680 }
681
685 public function getReportPanel(array $a_data): string
686 {
687 $modal = $this->getEvaluationModal($a_data);
688
689 $this->ctrl->setParameter($this, "member_id", $a_data['uid']);
690 $actions = array(
691 $this->ui_factory->button()->shy($this->lng->txt("grade_evaluate"), "#")->withOnClick($modal->getShowSignal())
692 );
693
694 if ($this->exercise->hasTutorFeedbackMail()) {
695 $actions[] = $this->ui_factory->button()->shy(
696 $this->lng->txt("exc_tbl_action_feedback_mail"),
697 $this->ctrl->getLinkTarget($this, "redirectFeedbackMail")
698 );
699 }
700 if ($this->exercise->hasTutorFeedbackFile()) {
701 $actions[] = $this->ui_factory->button()->shy(
702 $this->lng->txt("exc_tbl_action_feedback_file"),
703 $this->ctrl->getLinkTargetByClass(ilResourceCollectionGUI::class)
704 );
705 }
706
707 $this->ctrl->setParameter($this, "member_id", "");
708
709 $actions_dropdown = $this->ui_factory->dropdown()->standard($actions);
710 if ($a_data['status'] == self::GRADE_NOT_GRADED) {
711 $str_status_key = $this->lng->txt('exc_tbl_status') . ": ";
712 $str_status_value = "-";
713 } else {
714 $str_status_key = $this->lng->txt('exc_tbl_status_time') . ": ";
715 $str_status_value = ilDatePresentation::formatDate(new ilDateTime($a_data["status_time"], IL_CAL_DATETIME));
716 }
717
718 $str_mark_key = $this->lng->txt("exc_tbl_mark") . ": ";
719 $str_mark_value = "-";
720
721 if (($a_data['mark'] != "")) {
722 $str_mark_value = $a_data['mark'];
723 }
724
725 if ($a_data['feedback_time']) {
726 $str_evaluation_key = $this->lng->txt('exc_tbl_feedback_time') . ": ";
727 $str_evaluation_value = ilDatePresentation::formatDate(new ilDateTime($a_data["feedback_time"], IL_CAL_DATETIME));
728 } else {
729 $str_evaluation_key = $this->lng->txt('exc_settings_feedback') . ": ";
730 $str_evaluation_value = "-";
731 }
732
733 $card_content = array(
734 $this->lng->txt("exc_tbl_submission_date") . ": " => ilDatePresentation::formatDate(new ilDateTime($a_data["udate"], IL_CAL_DATETIME)),
735 $str_status_key => $str_status_value,
736 $str_mark_key => $str_mark_value,
737 $str_evaluation_key => $str_evaluation_value,
738 $this->lng->txt('feedback_given') . ": " => $a_data['fb_given'],
739 $this->lng->txt('feedback_received') . ": " => $a_data['fb_received']
740 );
741 $card_tpl = new ilTemplate("tpl.exc_report_details_card.html", true, true, "components/ILIAS/Exercise");
742 foreach ($card_content as $key => $value) {
743 $card_tpl->setCurrentBlock("assingment_card");
744 $card_tpl->setVariable("ROW_KEY", $key);
745 $card_tpl->setVariable("ROW_VALUE", $value);
746 $card_tpl->parseCurrentBlock();
747 }
748
749 $main_panel = $this->ui_factory->panel()->sub($a_data['uname'], $this->ui_factory->legacy()->content(
750 $this->gui->html()->escapeCurly($a_data['utext'])
751 ))
752 ->withFurtherInformation($this->ui_factory->card()->standard($this->lng->txt('text_assignment'))->withSections(array($this->ui_factory->legacy()->content($card_tpl->get()))))->withActions($actions_dropdown);
753
754 $feedback_tpl = new ilTemplate("tpl.exc_report_feedback.html", true, true, "components/ILIAS/Exercise");
755 //if no feedback filter the feedback is displayed. Can be list submissions or compare submissions.
756 $filter_feedback = $this->filter["feedback"] ?? "";
757 if (array_key_exists("peer", $a_data) && (($filter_feedback == self::FEEDBACK_FULL_SUBMISSION) || $filter_feedback == "")) {
758 $feedback_tpl->setCurrentBlock("feedback");
759 foreach ($a_data["peer"] as $peer_id) {
760 if (ilObject::_lookupType($peer_id) == "usr") {
761 $user = new ilObjUser($peer_id);
762 $peer_name = $user->getFirstname() . " " . $user->getLastname();
763 } else {
764 $peer_name = $this->lng->txt("exc_deleted_user");
765 }
766
767 $feedback_tpl->setCurrentBlock("peer_feedback");
768 $feedback_tpl->setVariable("PEER_NAME", $peer_name);
769
770 $submission = new ilExSubmission($this->assignment, $a_data["uid"]);
771 $values = $submission->getPeerReview()->getPeerReviewValues($peer_id, $a_data["uid"]);
772
773 $review_html = "";
774 foreach ($this->assignment->getPeerReviewCriteriaCatalogueItems() as $crit) {
775 $crit_id = $crit->getId()
776 ? $crit->getId()
777 : $crit->getType();
778 $crit->setPeerReviewContext($this->assignment, $peer_id, $a_data["uid"]);
779
780 $review_html .=
781 '<div class="ilBlockPropertyCaption">' . $crit->getTitle() . '</div>' .
782 '<div style="margin:2px 0;">' . $crit->getHTML($values[$crit_id] ?? null) . '</div>';
783 }
784 $feedback_tpl->setVariable("PEER_FEEDBACK", $review_html);
785 $feedback_tpl->parseCurrentBlock();
786 }
787 $feedback_tpl->parseCurrentBlock();
788 }
789 $feedback_tpl->setVariable("GRADE", $this->lng->txt('exc_grading') . ": " . $this->lng->txt('exc_' . $a_data['status']));
790 $comment = ($a_data['comment'] === "")
791 ? "-"
792 : $a_data['comment'];
793 $feedback_tpl->setVariable("COMMENT", $this->lng->txt('exc_comment') . ": <br>" . $comment);
794
795 $feedback_panel = $this->ui_factory->panel()->sub("", $this->ui_factory->legacy()->content($feedback_tpl->get()));
796
797 $report = $this->ui_factory->panel()->report("", array($main_panel, $feedback_panel));
798
799 return $this->ui_renderer->render([$modal,$report]);
800 }
801
802 public function getEvaluationModal(
803 array $a_data
804 ): RoundTrip {
805 $modal_tpl = new ilTemplate("tpl.exc_report_evaluation_modal.html", true, true, "components/ILIAS/Exercise");
806 $modal_tpl->setVariable("USER_NAME", $a_data['uname']);
807
808 $form = $this->getEvaluationModalForm($a_data);
809 //TODO: CHECK ilias string utils. ilUtil shortenText with net blank.
810 if ($this->exercise->hasTutorFeedbackText()) {
811 $max_chars = 500;
812
813 $u_text = strip_tags($a_data["utext"]); //otherwise will get open P
814 $text = $u_text;
815 //show more
816 if (strlen($u_text) > $max_chars) {
817 $text = "<input type='checkbox' class='read-more-state' id='post-1' />";
818 $text .= "<div class='read-more-wrap'>";
819 $text .= mb_substr($u_text, 0, $max_chars);
820 $text .= "<span class='read-more-target'>";
821 $text .= mb_substr($u_text, $max_chars);
822 $text .= "</span></div>";
823 $text .= "<label for='post-1' class='read-more-trigger'></label>";
824 }
825 $modal_tpl->setVariable("USER_TEXT", $text);
826 }
827
828 $modal_tpl->setVariable("FORM", $form->getHTML());
829
830 $form_id = 'form_' . $form->getId();
831 $submit_btn = $this->ui_factory->button()->primary($this->lng->txt("save"), '#')
832 ->withOnLoadCode(function ($id) use ($form_id) {
833 return "$('#$id').click(function() { $('#$form_id').submit(); return false; });";
834 });
835
836 return $this->ui_factory->modal()->roundtrip(strtoupper($this->lng->txt("grade_evaluate")), $this->ui_factory->legacy()->content($modal_tpl->get()))->withActionButtons([$submit_btn]);
837 }
838
839 public function getEvaluationModalForm(
840 array $a_data
842 $form = new ilPropertyFormGUI();
843 $form->setFormAction($this->ctrl->getFormAction($this, "saveEvaluationFromModal"));
844 $form->setId(uniqid('form'));
845
846 //Grade
847 $options = array(
848 self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
849 self::GRADE_PASSED => $this->lng->txt("exc_passed"),
850 self::GRADE_FAILED => $this->lng->txt("exc_failed")
851 );
852 $si = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "grade");
853 $si->setOptions($options);
854 $si->setValue($a_data['status'] ?? "");
855 $form->addItem($si);
856
857 //Mark
858 $mark_input = new ilTextInputGUI($this->lng->txt("exc_tbl_mark"), "mark");
859 $mark_input->setValue($a_data['mark'] ?? "");
860 $mark_input->setMaxLength(32);
861 $mark_input->setSize(4);
862 $form->addItem($mark_input);
863
864 $item = new ilHiddenInputGUI('mem_id');
865 $item->setValue($a_data['uid'] ?? "");
866 $form->addItem($item);
867
868 //TODO: CHECK ilias string utils. ilUtil shortenText with net blank.
869 if ($this->exercise->hasTutorFeedbackText()) {
870 $ta = new ilTextAreaInputGUI($this->lng->txt("exc_comment"), 'comment');
871 $ta->setInfo($this->lng->txt("exc_comment_for_learner_info"));
872 $ta->setValue($a_data['comment'] ?? "");
873 $ta->setRows(10);
874 $form->addItem($ta);
875 }
876 return $form;
877 }
878
879 // Save assignment submission grade(status) and comment from the roundtrip modal.
880
884 public function saveEvaluationFromModalObject(): void
885 {
886 $form = $this->getEvaluationModalForm([]);
887 $user_id = 0;
888 $comment = "";
889 $mark = "";
890 $grade = "";
891 if ($form->checkInput()) {
892 $comment = trim($form->getInput('comment'));
893 $user_id = (int) $form->getInput('mem_id');
894 $grade = trim($form->getInput('grade'));
895 $mark = trim($form->getInput('mark'));
896 }
897
898 if ($this->assignment->getId() && $user_id > 0) {
899 $member_status = $this->assignment->getMemberStatus($user_id);
900 $member_status->setComment(ilUtil::stripSlashes($comment));
901 if ($grade != "") {
902 $member_status->setStatus($grade);
903 }
904 $member_status->setMark($mark);
905 if ($comment != "") {
906 $member_status->setFeedback(true);
907 }
908 $member_status->update();
909 }
910 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_status_saved"), true);
911 $this->ctrl->redirect($this, "listTextAssignment");
912 }
913
914 // Add user as member
915
919 public function addUserFromAutoCompleteObject(): void
920 {
921 if ($this->requested_user_login == "") {
922 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('msg_no_search_string'));
923 $this->membersObject();
924 return;
925 }
926 $users = explode(',', $this->requested_user_login);
927
928 $user_ids = array();
929 foreach ($users as $user) {
931
932 if (!$user_id) {
933 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('user_not_known'));
934 $this->membersObject();
935 return;
936 }
937
938 $user_ids[] = $user_id;
939 }
940
941 $this->addMembersObject($user_ids);
942 }
943
944 // Add new partipant
945 public function addMembersObject($a_user_ids = array()): void
946 {
947 if (!count($a_user_ids)) {
948 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
949 } else {
950 if (!$this->exercise->members_obj->assignMembers($a_user_ids)) {
951 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("exc_members_already_assigned"), true);
952 } else {
953 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_members_assigned"), true);
954 }
955 }
956 $this->ctrl->redirect($this, "members");
957 }
958
962 public function selectAssignmentObject(): void
963 {
964 $ctrl = $this->ctrl;
965 $ctrl->setParameter($this, "ass_id", $this->requested_ass_id);
966 $ctrl->redirect($this, "members");
967 }
968
972 public function showParticipantObject(): void
973 {
974 $tpl = $this->tpl;
975 $ilToolbar = $this->toolbar;
976 $ilCtrl = $this->ctrl;
978 $access = $this->access;
979
980 $this->addSubTabs("participant");
981 $this->ctrl->setParameter($this, "ass_id", "0");
982
983 // participant selection
984 $members = $this->exercise->members_obj->getMembers();
985
987 'edit_submissions_grades',
988 'edit_submissions_grades',
989 $this->exercise->getRefId(),
990 $members
991 );
992
993
994 if (count($members) == 0) {
995 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_no_participants"));
996 return;
997 }
998
999 $mems = array();
1000 foreach ($members as $mem_id) {
1001 if (ilObject::_lookupType($mem_id) == "usr") {
1002 $name = ilObjUser::_lookupName($mem_id);
1003 if (trim($name["login"]) != "") { // #20073
1004 $mems[$mem_id] = $name;
1005 }
1006 }
1007 }
1008
1009 $mems = ilArrayUtil::sortArray($mems, "lastname", "asc", false, true);
1010
1011 if ($this->requested_part_id == 0 && $mems !== [] && key($mems) > 0) {
1012 $ilCtrl->setParameter($this, "part_id", key($mems));
1013 $ilCtrl->redirect($this, "showParticipant");
1014 }
1015
1016 $current_participant = $this->requested_part_id;
1017
1018 reset($mems);
1019 if (count($mems) > 1) {
1020 $options = array();
1021 foreach ($mems as $k => $m) {
1022 $options[$k] =
1023 $m["lastname"] . ", " . $m["firstname"] . " [" . $m["login"] . "]";
1024 }
1025 $si = new ilSelectInputGUI($this->lng->txt("exc_participant"), "part_id");
1026 $si->setOptions($options);
1027 $si->setValue($current_participant);
1028 $ilToolbar->addStickyItem($si, true);
1029
1030 $this->gui->button(
1031 $this->lng->txt("select"),
1032 "selectParticipant"
1033 )->submit()->toToolbar(true);
1034 }
1035
1036 if ($mems !== []) {
1037 $this->ctrl->setParameter($this, "vw", self::VIEW_PARTICIPANT);
1038 $this->ctrl->setParameter($this, "part_id", $current_participant);
1039
1040 $ilToolbar->addSeparator();
1041 $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
1042 $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
1043
1045 $this,
1046 "showParticipant",
1047 $this->exercise,
1048 $current_participant,
1049 $this->feedback_gui
1050 );
1051 $tpl->setContent($part_tab->getHTML() .
1052 $this->initIndividualDeadlineModal());
1053 } else {
1054 $this->tpl->setOnScreenMessage('info', $this->lng->txt("exc_no_assignments_available"));
1055 }
1056 }
1057
1060 public function showParticipantApplyObject(): void
1061 {
1063 $this,
1064 "showParticipant",
1065 $this->exercise,
1066 $this->requested_part_id,
1067 $this->feedback_gui
1068 );
1069 $exc_tab->resetOffset();
1070 $exc_tab->writeFilterToSession();
1071
1072 $this->showParticipantObject();
1073 }
1074
1077 public function showParticipantResetObject(): void
1078 {
1080 $this,
1081 "showParticipant",
1082 $this->exercise,
1083 $this->requested_part_id,
1084 $this->feedback_gui
1085 );
1086 $exc_tab->resetOffset();
1087 $exc_tab->resetFilter();
1088
1089 $this->showParticipantObject();
1090 }
1091
1095 public function selectParticipantObject(): void
1096 {
1097 $ctrl = $this->ctrl;
1098 $ctrl->setParameter($this, "part_id", $this->requested_part_id);
1099 $ctrl->redirect($this, "showParticipant");
1100 }
1101
1102 public function showGradesOverviewObject(): void
1103 {
1104 $tpl = $this->tpl;
1105 $ilToolbar = $this->toolbar;
1106 $ilCtrl = $this->ctrl;
1107 $lng = $this->lng;
1108
1109 $this->addSubTabs("grades");
1110
1111 $mem_obj = new ilExerciseMembers($this->exercise);
1112 $mems = $mem_obj->getMembers();
1113
1114 $mems = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1115 'edit_submissions_grades',
1116 'edit_submissions_grades',
1117 $this->exercise->getRefId(),
1118 $mems
1119 );
1120 if (count($mems) > 0) {
1121 $ilToolbar->addButton(
1122 $lng->txt("exc_export_excel"),
1123 $ilCtrl->getLinkTarget($this, "exportExcel")
1124 );
1125 }
1126
1127 $this->ctrl->setParameter($this, "vw", self::VIEW_GRADES);
1128
1129 $grades_tab = new ilExGradesTableGUI(
1130 $this,
1131 "showGradesOverview",
1132 $this->service,
1133 $mem_obj
1134 );
1135 $tpl->setContent($grades_tab->getHTML());
1136 }
1137
1141 public function redirectFeedbackMailObject(): void
1142 {
1143 if ($this->requested_member_id > 0) {
1144 $submission = new ilExSubmission($this->assignment, $this->requested_member_id);
1145 $members = $submission->getUserIds();
1146 } elseif ($members = $this->getMultiActionUserIds()) {
1147 $members = array_keys($members);
1148 }
1149
1150 if ($members !== []) {
1151 $logins = array();
1152 foreach ($members as $user_id) {
1153 $member_status = $this->assignment->getMemberStatus($user_id);
1154 $member_status->setFeedback(true);
1155 $member_status->update();
1156
1157 $logins[] = ilObjUser::_lookupLogin($user_id);
1158 }
1159 $logins = implode(",", $logins);
1160
1161 // #16530 - see ilObjCourseGUI::createMailSignature
1162 $sig = chr(13) . chr(10) . chr(13) . chr(10);
1163 $sig .= $this->lng->txt('exc_mail_permanent_link');
1164 $sig .= chr(13) . chr(10) . chr(13) . chr(10);
1165 $sig .= ilLink::_getLink($this->exercise->getRefId());
1166 $sig = rawurlencode(base64_encode($sig));
1167
1169 $this,
1170 $this->getViewBack(),
1171 array(),
1172 array(
1173 'type' => 'new',
1174 'rcp_to' => $logins,
1176 )
1177 ));
1178 }
1179 }
1180
1181 // Download all submitted files (of all members).
1182
1186 protected function getMultiActionUserIds(bool $a_keep_teams = false): array
1187 {
1188 $members = [];
1189 // multi-user
1190 if ($this->assignment !== null) {
1191 if (count($this->selected_participants) == 0) {
1192 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
1193 $this->ctrl->redirect($this, "members");
1194 }
1195
1196 foreach ($this->selected_participants as $user_id) {
1197 $submission = new ilExSubmission($this->assignment, $user_id);
1198 $tmembers = $submission->getUserIds();
1199 if (!$a_keep_teams) {
1200 foreach ($tmembers as $tuser_id) {
1201 $members[$tuser_id] = 1;
1202 }
1203 } else {
1204 if ($tmembers) {
1205 $members[] = $tmembers;
1206 } else {
1207 // no team yet
1208 $members[] = $user_id;
1209 }
1210 }
1211 }
1212 }
1213 // multi-ass
1214 else {
1215 if (count($this->selected_ass_ids) == 0) {
1216 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
1217 $this->ctrl->redirect($this, "showParticipant");
1218 }
1219
1220 $user_id = $this->requested_part_id;
1221
1222 foreach ($this->selected_ass_ids as $ass_id) {
1223 $submission = new ilExSubmission(new ilExAssignment($ass_id), $user_id);
1224 $tmembers = $submission->getUserIds();
1225 if (!$a_keep_teams) {
1226 foreach ($tmembers as $tuser_id) {
1227 $members[$ass_id][] = $tuser_id;
1228 }
1229 } else {
1230 if ($tmembers) {
1231 $members[$ass_id][] = $tmembers;
1232 } else {
1233 // no team yet
1234 $members[$ass_id][] = $user_id;
1235 }
1236 }
1237 }
1238 }
1239
1240 return $members;
1241 }
1242
1243 // Send assignment per mail to participants
1244
1248 public function sendMembersObject(): void
1249 {
1250 $members = $this->getMultiActionUserIds();
1251
1252 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_sent"), true);
1253 if ($this->assignment !== null) {
1254 $this->exercise->sendAssignment($this->assignment, array_keys($members));
1255 $this->ctrl->redirect($this, "members");
1256 } else {
1257 foreach ($members as $ass_id => $users) {
1258 $this->exercise->sendAssignment(new ilExAssignment($ass_id), $users);
1259 }
1260 $this->ctrl->setParameter($this, "part_id", $this->requested_part_id); // #17629
1261 $this->ctrl->redirect($this, "showParticipant");
1262 }
1263 }
1264
1268 public function confirmDeassignMembersObject(): void
1269 {
1270 $ilCtrl = $this->ctrl;
1271 $tpl = $this->tpl;
1272 $lng = $this->lng;
1273
1274 $members = $this->getMultiActionUserIds();
1275
1276 $cgui = new ilConfirmationGUI();
1277 $cgui->setFormAction($ilCtrl->getFormAction($this));
1278 $cgui->setHeaderText($lng->txt("exc_msg_sure_to_deassign_participant"));
1279 $cgui->setCancel($lng->txt("cancel"), "members");
1280 $cgui->setConfirm($lng->txt("remove"), "deassignMembers");
1281 foreach ($members as $k => $m) {
1282 $cgui->addItem(
1283 "member_ids[]",
1284 $k,
1285 ilUserUtil::getNamePresentation((int) $k, false, false, "", true)
1286 );
1287 }
1288
1289 $tpl->setContent($cgui->getHTML());
1290 }
1291
1292 // Deassign members from exercise
1293
1297 public function deassignMembersObject(): void
1298 {
1299 $ilCtrl = $this->ctrl;
1300 $lng = $this->lng;
1301
1302 $member_ids = $this->request->getMemberIds();
1303
1304 foreach ($member_ids as $usr_id) {
1305 $this->exercise->members_obj->deassignMember((int) $usr_id);
1306 }
1307 $this->tpl->setOnScreenMessage('success', $lng->txt("exc_msg_participants_removed"), true);
1308 $ilCtrl->redirect($this, "members");
1309 }
1310
1315 public function saveStatusParticipantObject(?array $selected_ass_ids = null): void
1316 {
1317 $ilCtrl = $this->ctrl;
1318
1319 $member_id = $this->requested_part_id;
1320 $data = array();
1321 $marks = $this->requested_marks;
1322 $status = $this->requested_status;
1323 $notices = $this->requested_tutor_notices;
1324 foreach ($this->listed_ass_ids as $ass_id) {
1325 if (is_array($selected_ass_ids) &&
1326 !in_array($ass_id, $selected_ass_ids)) {
1327 continue;
1328 }
1329
1330 $data[$ass_id][$member_id] = array(
1331 "status" => $status[$ass_id] ?? ""
1332 );
1333 if (isset($marks[$ass_id])) {
1334 $data[$ass_id][$member_id]["mark"] = $marks[$ass_id];
1335 }
1336 if (isset($notices[$ass_id])) {
1337 $data[$ass_id][$member_id]["notice"] = $notices[$ass_id];
1338 }
1339 }
1340
1341 $ilCtrl->setParameter($this, "part_id", $member_id); // #17629
1342 $this->saveStatus($data);
1343 }
1344
1348 public function saveStatusAllObject(
1349 ?array $a_selected = null,
1350 bool $a_redirect = true
1351 ): void {
1352 $user_ids = $this->listed_participants;
1353 $marks = $this->requested_marks;
1354 $notices = $this->requested_tutor_notices;
1355 $status = $this->requested_status;
1356 $filtered_user_ids = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1357 'edit_submissions_grades',
1358 'edit_submissions_grades',
1359 $this->exercise->getRefId(),
1360 $user_ids
1361 );
1362
1363 $data = array();
1364 foreach ($filtered_user_ids as $user_id) {
1365 if (is_array($a_selected) &&
1366 !in_array($user_id, $a_selected)) {
1367 continue;
1368 }
1369
1370 $data[-1][$user_id] = array(
1371 "status" => $status[$user_id] ?? null
1372 );
1373
1374 if (isset($marks[$user_id])) {
1375 $data[-1][$user_id]["mark"] = $marks[$user_id];
1376 }
1377 if (isset($notices[$user_id])) {
1378 $data[-1][$user_id]["notice"] = $notices[$user_id];
1379 }
1380 }
1381 $this->saveStatus($data, $a_redirect);
1382 }
1383
1387 public function saveStatusSelectedObject(): void
1388 {
1389 //$members = $this->getMultiActionUserIds();
1390 if ($this->assignment !== null) {
1391 $this->saveStatusAllObject($this->selected_participants);
1392 } else {
1393 $this->saveStatusParticipantObject($this->selected_ass_ids);
1394 }
1395 }
1396
1397 // Save status of selected members
1398
1402 protected function saveStatus(
1403 array $a_data,
1404 bool $a_redirect = true
1405 ): void {
1406 $ilCtrl = $this->ctrl;
1407 $saved_for = array();
1408 foreach ($a_data as $ass_id => $users) {
1409 $ass = ($ass_id < 0)
1410 ? $this->assignment
1411 : new ilExAssignment($ass_id);
1412 foreach ($users as $user_id => $values) {
1413 // this will add team members if available
1414 // $user_id is only the ID of one team member here,
1415 // $sub_user_id will be all team members
1416 $submission = new ilExSubmission($ass, $user_id);
1417 foreach ($submission->getUserIds() as $sub_user_id) {
1418 $uname = ilObjUser::_lookupName($sub_user_id);
1419 $saved_for[$sub_user_id] = $uname["lastname"] . ", " . $uname["firstname"];
1420
1421 $member_status = $ass->getMemberStatus($sub_user_id);
1422
1423 // see bug #22566
1424 $status = $values["status"];
1425 if ($status == "") {
1426 $status = self::GRADE_NOT_GRADED;
1427 }
1428 $member_status->setStatus($status);
1429 if (array_key_exists("mark", $values)) {
1430 $member_status->setMark($values["mark"]);
1431 }
1432 if (array_key_exists("notice", $values)) {
1433 $member_status->setNotice($values["notice"]);
1434 }
1435 $member_status->update();
1436 }
1437 }
1438 }
1439
1440 $save_for_str = "";
1441 if ($saved_for !== []) {
1442 $save_for_str = "(" . implode(" - ", $saved_for) . ")";
1443 }
1444
1445 if ($a_redirect) {
1446 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_status_saved") . " " . $save_for_str, true);
1447 $ilCtrl->redirect($this, $this->getViewBack());
1448 }
1449 }
1450
1451 public function exportExcelObject(): void
1452 {
1453 $this->exercise->exportGradesExcel();
1454 exit;
1455 }
1456
1457
1458 //
1459 // TEAM
1460 //
1461
1465 public function createTeamsObject(): void
1466 {
1467 $ilCtrl = $this->ctrl;
1468
1469 $members = $this->getMultiActionUserIds(true);
1470
1471 $new_members = array();
1472
1473 foreach ($members as $group) {
1474 if (is_array($group)) {
1475 $new_members = array_merge($new_members, $group);
1476
1477 $first_user = $group;
1478 $first_user = array_shift($first_user);
1479 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1480 foreach ($group as $user_id) {
1481 $team->removeTeamMember($user_id);
1482 }
1483 } else {
1484 $new_members[] = $group;
1485 }
1486 }
1487
1488 if ($new_members !== []) {
1489 // see ilExSubmissionTeamGUI::addTeamMemberActionObject()
1490
1491 $first_user = array_shift($new_members);
1492 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user, true);
1493 foreach ($new_members as $user_id) {
1494 $team->addTeamMember($user_id);
1495 }
1496
1497 // re-evaluate complete team, as some members might have had submitted
1498 $submission = new ilExSubmission($this->assignment, $first_user);
1499 $this->exercise->processExerciseStatus(
1500 $this->assignment,
1501 $team->getMembers(),
1502 $submission->hasSubmitted(),
1503 $submission->validatePeerReviews()
1504 );
1505 }
1506
1507 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1508 $ilCtrl->redirect($this, "members");
1509 }
1510
1514 public function dissolveTeamsObject(): void
1515 {
1516 $ilCtrl = $this->ctrl;
1517
1518 $members = $this->getMultiActionUserIds(true);
1519
1520 foreach ($members as $group) {
1521 // if single member - nothing to do
1522 if (is_array($group)) {
1523 // see ilExSubmissionTeamGUI::removeTeamMemberObject()
1524
1525 $first_user = $group;
1526 $first_user = array_shift($first_user);
1527 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1528 foreach ($group as $user_id) {
1529 $team->removeTeamMember($user_id);
1530 }
1531
1532 // reset ex team members, as any submission is not valid without team
1533 $this->exercise->processExerciseStatus(
1534 $this->assignment,
1535 $group,
1536 false
1537 );
1538 }
1539 }
1540
1541 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1542 $ilCtrl->redirect($this, "members");
1543 }
1544
1546 ?ilPropertyFormGUI $a_form = null
1547 ): void {
1548 $ilCtrl = $this->ctrl;
1549 $ilTabs = $this->tabs_gui;
1550 $lng = $this->lng;
1551 $tpl = $this->tpl;
1552
1553 $ilTabs->clearTargets();
1554 $ilTabs->setBackTarget(
1555 $lng->txt("back"),
1556 $ilCtrl->getLinkTarget($this, $this->getViewBack())
1557 );
1558
1559 if ($a_form === null) {
1560 $a_form = $this->initGroupForm();
1561 }
1562 $tpl->setContent($a_form->getHTML());
1563 }
1564
1565 protected function initGroupForm(): ilPropertyFormGUI
1566 {
1567 $lng = $this->lng;
1568
1569 $form = new ilPropertyFormGUI();
1570 $form->setTitle($lng->txt("exc_adopt_group_teams") . " - " . $this->assignment->getTitle());
1571 $form->setFormAction($this->ctrl->getFormAction($this, "createTeamsFromGroups"));
1572
1573 $all_members = array();
1574 foreach (ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId()) as $grp_id => $group) {
1575 if (count($group["members"]) !== 0) {
1576 $grp_team = new ilCheckboxGroupInputGUI($lng->txt("obj_grp") . " \"" . $group["title"] . "\"", "grpt[" . $grp_id . "]");
1577 $grp_value = $options = array();
1578 foreach ($group["members"] as $user_id) {
1579 $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1580 $options[$user_id] = $user_name;
1581 if (!in_array($user_id, $all_members)) {
1582 $grp_value[] = $user_id;
1583 $all_members[] = $user_id;
1584 }
1585 }
1586 asort($options);
1587 foreach ($options as $user_id => $user_name) {
1588 $grp_team->addOption(new ilCheckboxOption($user_name, $user_id));
1589 }
1590 $grp_team->setValue($grp_value);
1591 } else {
1592 $grp_team = new ilNonEditableValueGUI($group["title"]);
1593 $grp_team->setValue($lng->txt("exc_adopt_group_teams_no_members"));
1594 }
1595 $form->addItem($grp_team);
1596 }
1597
1598 if ($all_members !== []) {
1599 $form->addCommandButton("createTeamsFromGroups", $lng->txt("save"));
1600 }
1601 $form->addCommandButton("members", $lng->txt("cancel"));
1602
1603 return $form;
1604 }
1605
1609 public function createTeamsFromGroupsObject(): void
1610 {
1611 $lng = $this->lng;
1612
1613 $req_members = $this->requested_group_members;
1614
1615 $form = $this->initGroupForm();
1616 if ($form->checkInput()) {
1617 $map = ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId());
1618 $all_members = $teams = array();
1619 $valid = true;
1620 foreach (array_keys($map) as $grp_id) {
1621 if (isset($req_members[$grp_id]) && is_array($req_members[$grp_id])) {
1622 $members = $req_members[$grp_id];
1623 $teams[] = $members;
1624 $invalid_team_members = array();
1625
1626 foreach ($members as $user_id) {
1627 if (!array_key_exists($user_id, $all_members)) {
1628 $all_members[$user_id] = $grp_id;
1629 } else {
1630 // user is selected in multiple groups
1631 $invalid_team_members[] = $user_id;
1632 }
1633 }
1634
1635 if ($invalid_team_members !== []) {
1636 $valid = false;
1637
1638 $alert = array();
1639 foreach ($invalid_team_members as $user_id) {
1640 $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1641 $grp_title = $map[$all_members[$user_id]]["title"];
1642 $alert[] = sprintf($lng->txt("exc_adopt_group_teams_conflict"), $user_name, $grp_title);
1643 }
1644 $input = $form->getItemByPostVar("grpt[" . $grp_id . "]");
1645 $input->setAlert(implode("<br/>", $alert));
1646 }
1647 }
1648 }
1649 if ($valid) {
1650 if ($teams !== []) {
1651 $existing_users = array_keys(ilExAssignmentTeam::getAssignmentTeamMap($this->assignment->getId()));
1652
1653 // create teams from group selections
1654 $sum = array("added" => 0, "blocked" => 0);
1655 foreach ($teams as $members) {
1656 foreach ($members as $user_id) {
1657 if (!$this->exercise->members_obj->isAssigned($user_id)) {
1658 $this->exercise->members_obj->assignMember($user_id);
1659 }
1660
1661 if (!in_array($user_id, $existing_users)) {
1662 $sum["added"]++;
1663 } else {
1664 $sum["blocked"]++;
1665 }
1666 }
1667
1668 $first = array_shift($members);
1669 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first, true);
1670
1671 // getTeamId() does NOT send notification
1672 // $team->sendNotification($this->exercise->getRefId(), $first, "add");
1673
1674 foreach ($members as $user_id) {
1675 $team->addTeamMember($user_id);
1676 }
1677 }
1678
1679 $mess = array();
1680 if ($sum["added"] !== 0) {
1681 $mess[] = sprintf($lng->txt("exc_adopt_group_teams_added"), $sum["added"]);
1682 }
1683 if ($sum["blocked"] !== 0) {
1684 $mess[] = sprintf($lng->txt("exc_adopt_group_teams_blocked"), $sum["blocked"]);
1685 }
1686 if ($sum["added"] !== 0) {
1687 $this->tpl->setOnScreenMessage('success', implode(" ", $mess), true);
1688 } else {
1689 $this->tpl->setOnScreenMessage('failure', implode(" ", $mess), true);
1690 }
1691 }
1692 $this->ctrl->redirect($this, "members");
1693 } else {
1694 $this->tpl->setOnScreenMessage('failure', $lng->txt("form_input_not_valid"));
1695 }
1696 }
1697
1698 $form->setValuesByPost();
1699 $this->adoptTeamsFromGroupObject($form);
1700 }
1701
1702
1706
1707 public function getMultiFeedbackForm(int $a_ass_id): FormAdapterGUI
1708 {
1709 $lng = $this->lng;
1710
1711 $form = $this->gui->form([self::class], "uploadMultiFeedback")
1712 ->section("main", ilExAssignment::lookupTitle($a_ass_id))
1713 ->file(
1714 "mfzip",
1715 $lng->txt("exc_multi_feedback_file"),
1716 $this->handleMultiFeedbackUploadResult(...),
1717 "rc_id",
1718 "",
1719 1,
1720 ["application/zip"]
1721 );
1722 return $form;
1723 }
1724
1726 FileUpload $upload,
1727 UploadResult $result
1729 $feedback_zip = $this->domain->assignment()->tutorFeedbackZip();
1730 $rid = $feedback_zip->importFromUploadResult(
1731 $this->ass_id,
1732 $this->user->getId(),
1733 $result
1734 );
1735 return new \ILIAS\FileUpload\Handler\BasicHandlerResult(
1736 '',
1737 \ILIAS\FileUpload\Handler\HandlerResult::STATUS_OK,
1738 $rid,
1739 ''
1740 );
1741 }
1742
1743
1745 ?FormAdapterGUI $form = null
1746 ): void {
1747 $lng = $this->lng;
1748 $tpl = $this->tpl;
1749
1750 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_multi_feedb_info"));
1751
1752 $this->addSubTabs("assignment");
1753
1754 // #13719
1755 $this->gui->button(
1756 $this->lng->txt("exc_download_zip_structure"),
1757 $this->ctrl->getLinkTarget($this, "downloadMultiFeedbackZip")
1758 )->toToolbar();
1759
1760 if ($form === null) {
1761 $form = $this->getMultiFeedbackForm($this->assignment->getId());
1762 }
1763
1764 $tpl->setContent($form->render());
1765 }
1766
1770 public function downloadMultiFeedbackZipObject(): void
1771 {
1772 $st_file = $this->domain->assignment()->tutorFeedbackZip()->getMultiFeedbackStructureFile(
1773 $this->assignment,
1774 $this->exercise
1775 );
1776 $this->gui->httpUtil()->deliverString(
1777 $st_file->content,
1778 $st_file->filename,
1779 "application/zip"
1780 );
1781 }
1782
1786 public function uploadMultiFeedbackObject(): void
1787 {
1788 // #11983
1789 $form = $this->getMultiFeedbackForm($this->assignment->getId());
1790 if ($form->isValid()) {
1791 $this->ctrl->redirect($this, "showMultiFeedbackConfirmationTable");
1792 }
1793
1794 $this->showMultiFeedbackObject($form);
1795 }
1796
1801 {
1802 $tpl = $this->tpl;
1803
1804 $this->addSubTabs("assignment");
1805
1806 $tab = new ilFeedbackConfirmationTable2GUI($this, "showMultiFeedbackConfirmationTable", $this->assignment);
1807 $tpl->setContent($tab->getHTML());
1808 }
1809
1813 public function cancelMultiFeedbackObject(): void
1814 {
1815 $this->ctrl->redirect($this, "members");
1816 }
1817
1821 public function saveMultiFeedbackObject(): void
1822 {
1823 $feedback_zip = $this->domain->assignment()->tutorFeedbackZip();
1824 $feedback_zip->saveMultiFeedbackFiles(
1825 $this->exercise,
1826 $this->assignment->getId(),
1827 $this->user->getId(),
1828 $this->requested_files
1829 );
1830
1831 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1832 $this->ctrl->redirect($this, "members");
1833 }
1834
1835
1836 //
1837 // individual deadlines
1838 //
1839
1840 protected function initIndividualDeadlineModal(): string
1841 {
1842 $lng = $this->lng;
1843 $tpl = $this->tpl;
1844
1845 // prepare modal
1846 $modal = $this->ui_factory->modal()->roundtrip(
1847 $lng->txt("exc_individual_deadline"),
1848 $this->ui_factory->legacy()->content('<div id="ilExcIDlBody"></div>')
1849 );
1850 $show = $modal->getShowSignal()->getId();
1851 $close = $modal->getCloseSignal()->getId();
1852
1853 $ajax_url = $this->ctrl->getLinkTarget($this, "handleIndividualDeadlineCalls", "", true, false);
1854
1855 $tpl->addJavaScript("assets/js/ilExcIDl.js", true, 3);
1856 $tpl->addOnLoadCode("il.ExcIDl.init('" . $ajax_url . "','" . $show . "','" . $close . "');");
1857
1859
1860 return $this->ui_renderer->render($modal);
1861 }
1862
1867 array $a_data
1868 ): array {
1869 if ($a_data) {
1870 $map = array();
1871 $ass_tmp = array();
1872 foreach ($a_data as $item) {
1873 $item = explode("_", $item);
1874 $ass_id = $item[0];
1875 $user_id = $item[1];
1876
1877 if (!array_key_exists($ass_id, $ass_tmp)) {
1878 if ($this->assignment &&
1879 $ass_id == $this->assignment->getId()) {
1880 $ass_tmp[$ass_id] = $this->assignment;
1881 } else {
1882 $ass_tmp[$ass_id] = new ilExAssignment($ass_id);
1883 }
1884 }
1885
1886 $map[$ass_id][] = $user_id;
1887 }
1888
1889 return array($map, $ass_tmp);
1890 }
1891 return [];
1892 }
1893
1898 protected function handleIndividualDeadlineCallsObject(): void
1899 {
1900 $tpl = $this->tpl;
1901
1902 $this->ctrl->saveParameter($this, "part_id");
1903
1904 // from request "dn", see ilExcIdl.js
1905 if ($this->done) {
1906 $this->tpl->setOnScreenMessage('success', $this->lng->txt("settings_saved"), true);
1907 $this->ctrl->redirect($this, $this->assignment !== null
1908 ? "members"
1909 : "showParticipant");
1910 }
1911
1912 // initial form call
1913 if ($this->requested_idl_id != "") {
1914 $tmp = $this->parseIndividualDeadlineData(explode(",", $this->requested_idl_id));
1915 if (is_array($tmp)) {
1916 $form = $this->initIndividualDeadlineForm($tmp[1], $tmp[0]);
1917 echo $form->getHTML() .
1918 $tpl->getOnLoadCodeForAsynch();
1919 }
1920 }
1921 // form "submit"
1922 else {
1923 $tmp = array();
1924 $post = $this->http->request()->getParsedBody();
1925 foreach (array_keys($post) as $id) {
1926 if (substr($id, 0, 3) == "dl_") {
1927 $tmp[] = substr($id, 3);
1928 }
1929 }
1930 $tmp = $this->parseIndividualDeadlineData($tmp);
1931 $ass_map = $tmp[1];
1932 $users = $tmp[0];
1933 unset($tmp);
1934
1935 $form = $this->initIndividualDeadlineForm($ass_map, $users);
1936 $res = array();
1937 if ($valid = $form->checkInput()) {
1938 foreach ($users as $ass_id => $users2) {
1939 $ass = $ass_map[$ass_id];
1940
1941 // :TODO: should individual deadlines BEFORE extended be possible?
1942 $dl = new ilDateTime($ass->getDeadline(), IL_CAL_UNIX);
1943
1944 foreach ($users2 as $user_id) {
1945 $date_field = $form->getItemByPostVar("dl_" . $ass_id . "_" . $user_id);
1946 if (ilDate::_before($date_field->getDate(), $dl)) {
1947 $date_field->setAlert(sprintf($this->lng->txt("exc_individual_deadline_before_global"), ilDatePresentation::formatDate($dl)));
1948 $valid = false;
1949 } else {
1950 $res[$ass_id][$user_id] = $date_field->getDate();
1951 }
1952 }
1953 }
1954 }
1955
1956 if (!$valid) {
1957 $form->setValuesByPost();
1958 echo $form->getHTML() .
1959 $tpl->getOnLoadCodeForAsynch();
1960 } else {
1961 foreach ($res as $ass_id => $users) {
1962 $ass = $ass_map[$ass_id];
1963
1964 foreach ($users as $id => $date) {
1965 $ass->setIndividualDeadline($id, $date);
1966 if (is_numeric($id)) {
1967 $this->notification->sendDeadlineSetNotification($ass_id, $id);
1968 }
1969 }
1970
1971 $subm = $this->domain->submission($ass->getId());
1972 $subm->recalculateLateSubmissions();
1973 }
1974
1975 echo "ok";
1976 }
1977 }
1978
1979 exit();
1980 }
1981
1985 protected function initIndividualDeadlineForm(
1986 array $a_ass_map,
1987 array $ids
1989 $form = new ilPropertyFormGUI();
1990 $form->setFormAction($this->ctrl->getFormAction($this));
1991 $form->setName("ilExcIDlForm");
1992
1993 foreach ($ids as $ass_id => $users) {
1994 $ass = $a_ass_map[$ass_id];
1995
1996 $section = new ilFormSectionHeaderGUI();
1997 $section->setTitle($ass->getTitle());
1998 $form->addItem($section);
1999
2000 $teams = ilExAssignmentTeam::getInstancesFromMap($ass->getId());
2001
2002 $values = $ass->getIndividualDeadlines();
2003
2004 foreach ($users as $id) {
2005 // single user
2006 if (is_numeric($id)) {
2007 $name = ilObjUser::_lookupName($id);
2008 $name = $name["lastname"] . ", " . $name["firstname"];
2009 }
2010 // team
2011 else {
2012 $name = "";
2013 $team_id = (int) substr($id, 1);
2014 if (array_key_exists($team_id, $teams)) {
2015 $name = array();
2016 foreach ($teams[$team_id]->getMembers() as $member_id) {
2017 $uname = ilObjUser::_lookupName($member_id);
2018 $name[] = $uname["lastname"] . ", " . $uname["firstname"];
2019 }
2020 asort($name);
2021 $name = implode("<br />", $name);
2022 }
2023 }
2024
2025 $dl = new ilDateTimeInputGUI($name, "dl_" . $ass_id . "_" . $id);
2026 $dl->setShowTime(true);
2027 $dl->setRequired(true);
2028 $form->addItem($dl);
2029
2030 if (array_key_exists($id, $values)) {
2031 $dl->setDate(new ilDateTime($values[$id], IL_CAL_UNIX));
2032 }
2033 }
2034 }
2035
2036 $form->addCommandButton("", $this->lng->txt("save"));
2037
2038 return $form;
2039 }
2040
2044 protected function setIndividualDeadlineObject(): void
2045 {
2046 // this will only get called if no selection
2047 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("select_one"));
2048
2049 if ($this->assignment !== null) {
2050 $this->membersObject();
2051 } else {
2052 $this->showParticipantObject();
2053 }
2054 }
2055
2056 public function initFilter(): void
2057 {
2058 if ($this->requested_filter_status != "") {
2059 $this->filter["status"] = $this->requested_filter_status;
2060 }
2061
2062 $this->lng->loadLanguageModule("search");
2063
2064 $this->toolbar->setFormAction($this->ctrl->getFormAction($this, "listTextAssignment"));
2065
2066 // Status
2067
2068 $si_status = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "filter_status");
2069 $options = array(
2070 "" => $this->lng->txt("search_any"),
2071 self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
2072 self::GRADE_PASSED => $this->lng->txt("exc_passed"),
2073 self::GRADE_FAILED => $this->lng->txt("exc_failed")
2074 );
2075 $si_status->setOptions($options);
2076 $si_status->setValue($this->filter["status"] ?? "");
2077
2078 $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2079 $options = array(
2080 self::FEEDBACK_FULL_SUBMISSION => $this->lng->txt("submissions_feedback"),
2081 self::FEEDBACK_ONLY_SUBMISSION => $this->lng->txt("submissions_only")
2082 );
2083 $si_feedback->setOptions($options);
2084 $si_feedback->setValue($this->filter["feedback"] ?? "");
2085
2086 $this->toolbar->addInputItem($si_status, true);
2087
2088 // Submissions and Feedback
2089 #24713
2090 if ($this->assignment->getPeerReview()) {
2091 if ($this->requested_filter_feedback != "") {
2092 $this->filter["feedback"] = $this->requested_filter_feedback;
2093 } else {
2094 $this->filter["feedback"] = "submission_feedback";
2095 }
2096
2097 $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2098 $options = array(
2099 "submission_feedback" => $this->lng->txt("submissions_feedback"),
2100 "submission_only" => $this->lng->txt("submissions_only")
2101 );
2102 $si_feedback->setOptions($options);
2103 $si_feedback->setValue($this->filter["feedback"] ?? "");
2104
2105 $this->toolbar->addInputItem($si_feedback, true);
2106 }
2107
2108 $this->gui->button(
2109 $this->lng->txt("filter"),
2110 "listTextAssignment"
2111 )->submit()->toToolbar();
2112 }
2113
2117 public function openSubmissionPrintViewObject(): void
2118 {
2119 $this->openSubmissionViewObject(true);
2120 }
2121
2125 public function openSubmissionViewObject(bool $print_version = false): void
2126 {
2127 global $DIC;
2128
2129 $member_id = $this->requested_member_id;
2130
2131 $submission = new ilExSubmission($this->assignment, $member_id);
2132 $entry = $submission->getSubmittedEntry($print_version);
2133 if (is_null($entry)) {
2134 throw new ilExerciseException("No submission entry for " . $this->assignment->getId() . " / " .
2135 $member_id . ".");
2136 }
2137 $rid = $entry->getRid();
2138
2139 $last_opening = $submission->getLastOpeningHTMLView();
2140 $submission_time = $submission->getLastSubmission();
2141
2142 if ($rid !== "") {
2143 $zip_internal_path = "ilExercise/" . \ilFileSystemAbstractionStorage::createPathFromId(
2144 $this->assignment->getExerciseId(),
2145 "exc"
2146 ) . "/subm_" . $this->assignment->getId() . "/" . $member_id . "/resource.zip";
2147 $obj_id = str_replace([".zip", "print"], "", $entry->getTitle());
2148 $obj_id = $this->assignment->getAssignmentType()->getExportObjIdForResourceId($obj_id);
2149 }
2150 if ($print_version) {
2151 $obj_id .= "print";
2152 }
2153
2154 $obj_dir = $this->assignment->getAssignmentType()->getStringIdentifier() . "_" . $obj_id;
2155
2156 $index_html_file =
2158 DIRECTORY_SEPARATOR .
2159 CLIENT_ID .
2160 DIRECTORY_SEPARATOR .
2161 dirname($zip_internal_path) .
2162 //DIRECTORY_SEPARATOR .
2163 //$obj_dir .
2164 DIRECTORY_SEPARATOR .
2165 "index.html";
2166 $this->log->debug("index html file: " . $index_html_file);
2167
2168 $web_filesystem = $DIC->filesystem()->web();
2169 if ($last_opening > $submission_time && $web_filesystem->has($index_html_file)) {
2171 ilUtil::redirect($index_html_file);
2172 }
2173 $error_msg = "";
2174 if ($rid !== "") {
2175 $file_copied = $this->domain->submission($this->ass_id)->copyRidToWebDir($rid, $zip_internal_path);
2176 }
2177
2178 // e.g. data/ilias/ilExercise/3/exc_327/subm_9/2/20231212085734_167.zip ?
2179 if ($file_copied) {
2180 $this->zip->unzipFile($file_copied);
2181 $web_filesystem->delete($zip_internal_path);
2182 $this->log->debug("deleting: " . $zip_internal_path);
2183
2184 $submission_repository = $this->service->repo()->submission();
2185 $submission_repository->updateWebDirAccessTime($this->assignment->getId(), $member_id);
2187 ilUtil::redirect($index_html_file . "?" . time());
2188 }
2189
2190 $error_msg = $this->lng->txt("exc_copy_zip_error");
2191
2192 if ($error_msg === '' || $error_msg === '0') {
2193 $error_msg = $this->lng->txt("exc_find_zip_error");
2194 }
2195
2196 $this->tpl->setOnScreenMessage('failure', $error_msg);
2197 }
2198
2203 string $external_file_path
2204 ): string {
2205 list($external_path, $internal_file_path) = explode(CLIENT_ID . "/ilExercise", $external_file_path);
2206 $internal_file_path = "ilExercise" . $internal_file_path;
2207 return $internal_file_path;
2208 }
2209
2210 /*
2211 * Add the Back link to the tabs. (used in submission list and submission compare)
2212 */
2213 protected function setBackToMembers(): void
2214 {
2215 //tabs
2216 $this->tabs_gui->clearTargets();
2217 $this->tabs_gui->setBackTarget(
2218 $this->lng->txt("back"),
2219 $this->ctrl->getLinkTarget($this, "members")
2220 );
2221 }
2222
2224 int $user_id,
2225 string $ts,
2226 string $text
2227 ): array {
2228 $user = new ilObjUser($user_id);
2229 $uname = $user->getFirstname() . " " . $user->getLastname();
2230
2231 $data = array(
2232 "uid" => $user_id,
2233 "uname" => $uname,
2234 "udate" => $ts,
2235 "utext" => ilRTE::_replaceMediaObjectImageSrc($text, 1) // mob id to mob src
2236 );
2237
2238 //get data peer and assign it
2239 $peer_review = new ilExPeerReview($this->assignment);
2240 $data["peer"] = array();
2241 foreach ($peer_review->getPeerReviewsByPeerId($user_id) as $value) {
2242 $data["peer"][] = $value['giver_id'];
2243 }
2244
2245 $data["fb_received"] = count($data["peer"]);
2246 $data["fb_given"] = $peer_review->countGivenFeedback(true, $user_id);
2247
2248 return $data;
2249 }
2250
2251 public function sendGradingNotificationObject(): void
2252 {
2253
2254 $ass_id = $this->request->getAssId();
2255 $selected_users = $this->request->getSelectedParticipants();
2256
2257 $graded_users = array_filter($selected_users, function ($user_id) {
2258 return $this->assignment->getMemberStatus($user_id)->getStatus() !== "notgraded";
2259 });
2260
2261 if (count($graded_users) === 0) {
2262 $this->tpl->setOnScreenMessage("failure", $this->lng->txt("exc_no_graded_mem_selected"), true);
2263 $this->ctrl->redirect($this, $this->getViewBack());
2264 }
2265
2266 $not = new ilExerciseMailNotification();
2268 $not->setAssignmentId($ass_id);
2269 $not->setObjId($this->exercise->getId());
2270 $not->setRefId($this->exercise->getRefId());
2271 $not->setRecipients($graded_users);
2272 $not->send();
2273 $this->tpl->setOnScreenMessage("success", $this->lng->txt("exc_graded_mem_notified"), true);
2274 $this->ctrl->redirect($this, $this->getViewBack());
2275 }
2276
2277 protected function setFailedObject(): void
2278 {
2279 $members = $this->getMultiActionUserIds();
2280 $done = false;
2281 if ($this->assignment !== null) {
2282 foreach (array_keys($members) as $mem) {
2283 $done = true;
2284 $this->setSingleStatus($this->assignment->getId(), $mem, "failed");
2285 }
2286 if ($done) {
2287 $this->tpl->setOnScreenMessage("success", $this->lng->txt("msg_obj_modified"), true);
2288 }
2289 }
2290 $this->ctrl->redirect($this, "members");
2291 }
2292
2293 protected function setPassedObject(): void
2294 {
2295 $members = $this->getMultiActionUserIds();
2296 $done = false;
2297 if ($this->assignment !== null) {
2298 foreach (array_keys($members) as $mem) {
2299 $done = true;
2300 $this->setSingleStatus($this->assignment->getId(), $mem, "passed");
2301 }
2302 if ($done) {
2303 $this->tpl->setOnScreenMessage("success", $this->lng->txt("msg_obj_modified"), true);
2304 }
2305 }
2306 $this->ctrl->redirect($this, "members");
2307 }
2308
2309 protected function setSingleStatus($ass_id, $part_id, $status): void
2310 {
2311 $ass = new ilExAssignment($ass_id);
2312 $submission = new ilExSubmission($ass, $part_id);
2313 $member_status = $ass->getMemberStatus($part_id);
2314 $member_status->setStatus($status);
2315 $member_status->update();
2316 }
2317}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$comment
Definition: buildRTE.php:72
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:544
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Exercise gui request wrapper.
getTutorNotices()
key might be ass_ids or user_ids!
getMarks()
key might be ass_ids or user_ids!
getStatus()
key might be ass_ids or user_ids!
Exercise UI frontend presentation service class.
request(?array $query_params=null, ?array $post_data=null)
Get request wrapper.
const IL_CAL_UNIX
const IL_CAL_DATETIME
return true
static sortArray(array $array, string $a_array_sortby_key, string $a_array_sortorder="asc", bool $a_numeric=false, bool $a_keep_keys=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a property in a property form.
This class represents an option in a checkbox group.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilCtrl provides processing control methods.
setParameter(object $a_gui_obj, string $a_parameter, $a_value)
@inheritDoc
redirect(object $a_gui_obj, ?string $a_cmd=null, ?string $a_anchor=null, bool $is_async=false)
@inheritDoc
setParameterByClass(string $a_class, string $a_parameter, $a_value)
@inheritDoc
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
This class represents a date/time property in a property form.
@classDescription Date and time handling
static _before(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
compare two dates and check start is before end This method does not consider tz offsets.
Download submissions and feedback for exercises.
static getAssignmentTeamMap(int $a_ass_id)
static getAdoptableGroups(int $a_exc_ref_id)
static getInstanceByUserId(int $a_assignment_id, int $a_user_id, bool $a_create_on_demand=false)
static getInstancesFromMap(int $a_assignment_id)
static getGroupMembersMap(int $a_exc_ref_id)
Exercise assignment.
static getInstancesByExercise(int $a_exc_id)
static lookupTitle(int $a_id)
Exercise participant table.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Exercise peer review.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Exercise submission //TODO: This class has many static methods related to delivered "files".
static getAssignmentParticipants(int $a_exercise_id, int $a_ass_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
@ilCtrl_Calls ilExerciseManagementGUI: ilRepositorySearchGUI @ilCtrl_Calls ilExerciseManagementGUI: i...
ILIAS Exercise Notification NotificationManager $notification
initIndividualDeadlineForm(array $a_ass_map, array $ids)
handleMultiFeedbackUploadResult(FileUpload $upload, UploadResult $result)
uploadMultiFeedbackObject()
Upload multi feedback file.
collectFeedbackDataFromPeer(int $user_id, string $ts, string $text)
TutorFeedbackFileManager $tutor_feedback_file
saveStatus(array $a_data, bool $a_redirect=true)
getMultiActionUserIds(bool $a_keep_teams=false)
__construct(InternalService $service, ?ilExAssignment $a_ass=null)
Constructor.
adoptTeamsFromGroupObject(?ilPropertyFormGUI $a_form=null)
openSubmissionViewObject(bool $print_version=false)
Open HTML view for portfolio submissions.
showMultiFeedbackConfirmationTableObject()
Show multi feedback confirmation table.
saveMultiFeedbackObject()
Save multi feedback.
ilExerciseSubmissionFeedbackGUI $feedback_gui
showMultiFeedbackObject(?FormAdapterGUI $form=null)
getWebFilePathFromExternalFilePath(string $external_file_path)
Get the object specific file path from an external full file path.
openSubmissionPrintViewObject()
Open HTML view for portfolio submissions.
cancelMultiFeedbackObject()
Cancel Multi Feedback.
membersObject()
All participants and submission of one assignment.
saveStatusParticipantObject(?array $selected_ass_ids=null)
Save assignment status (participant view)
compareTextAssignmentsObject()
TODO -> Deal with the redirection after update the grade via action button.
setSingleStatus($ass_id, $part_id, $status)
downloadMultiFeedbackZipObject()
Download multi-feedback structrue file.
ILIAS Exercise InternalDomainService $domain
downloadSubmissionsObject(?array $selected_participants=null)
saveStatusAllObject(?array $a_selected=null, bool $a_redirect=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilExerciseMembers.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static createPathFromId(int $a_container_id, string $a_name)
setFormAction(string $a_formaction)
This class represents a section header in a property form.
This class represents a hidden form property in a property form.
language handling
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
Component logger with individual log levels by component id.
final const string SIGNATURE_KEY
static getRedirectTarget( $gui, string $cmd, array $gui_params=[], array $mail_params=[], array $context_params=[])
This class represents a non editable value in a property form.
Class ilObjExercise.
User class.
static _lookupName(int $a_user_id)
static _lookupId(string|array $a_user_str)
static _lookupLogin(int $a_user_id)
static _lookupType(int $id, bool $reference=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a property form user interface.
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static fillAutoCompleteToolbar(object $parent_object, ?ilToolbarGUI $toolbar=null, array $a_options=[], bool $a_sticky=false)
array( auto_complete_name = $lng->txt('user'), auto_complete_size = 15, user_type = array(ilCoursePar...
This class represents a selection list property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
special template class to simplify handling of ITX/PEAR
This class represents a text area property in a property form.
This class represents a text property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getNamePresentation( $a_user_id, bool $a_user_image=false, bool $a_profile_link=false, string $a_profile_back_link='', bool $a_force_first_lastname=false, bool $a_omit_login=false, bool $a_sortable=true, bool $a_return_data_array=false, $a_ctrl_path=null)
Default behaviour is:
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
static redirect(string $a_script)
static signFolderOfStartFile(string $start_file_path)
const CLIENT_ID
Definition: constants.php:41
const ILIAS_WEB_DIR
Definition: constants.php:45
$valid
exit
addJavaScript(string $a_js_file, bool $a_add_version_parameter=true, int $a_batch=2)
Add a javascript file that should be included in the header.
getOnLoadCodeForAsynch()
Get js onload code for ajax calls.
setOnScreenMessage(string $type, string $a_txt, bool $a_keep=false)
Set a message to be displayed to the user.
setContent(string $a_html)
Sets content for standard template.
addOnLoadCode(string $a_code, int $a_batch=2)
Add on load code.
This is how the factory for UI elements looks.
Definition: Factory.php:38
An entity that renders components to a string output.
Definition: Renderer.php:31
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
Interface ilDBInterface.
filterUserIdsByRbacOrPositionOfCurrentUser(string $rbac_perm, string $pos_perm, int $ref_id, array $user_ids)
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
$post
Definition: ltitoken.php:46
static http()
Fetches the global http state from ILIAS.
filter(string $filter_id, $class_path, string $cmd, bool $activated=true, bool $expanded=true)
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68
$GLOBALS["DIC"]
Definition: wac.php:54