ILIAS  trunk Revision v12.0_alpha-1227-g7ff6d300864
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
450 $mem_data = $this->assignment->getMemberListData();
451 if (count($mem_data) > 0) {
452 // multi-feedback
453 $ilToolbar->addButton(
454 $this->lng->txt("exc_multi_feedback"),
455 $this->ctrl->getLinkTarget($this, "showMultiFeedback")
456 );
457
458 $ilToolbar->addSeparator();
459 }
460 }
461 }
462
463 $submission_repository = $this->service->repo()->submission();
464
465 if ($submission_repository->hasSubmissions($this->assignment->getId()) !== 0) {
466 $ass_type = $this->assignment->getType();
467 //todo change addFormButton for addButtonInstance
468 if ($ass_type == ilExAssignment::TYPE_TEXT) {
469 $ilToolbar->addFormButton($lng->txt("exc_list_text_assignment"), "listTextAssignment");
470 }
471 $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
472 }
473 $this->ctrl->setParameter($this, "vw", self::VIEW_ASSIGNMENT);
474
476 $this,
477 "members",
478 $this->exercise,
479 $this->assignment->getId(),
480 $this->feedback_gui
481 );
483 $exc_tab->getHTML() .
484 $this->initIndividualDeadlineModal()
485 );
486 } else {
487 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_no_assignments_available"));
488 }
489
490 $ilCtrl->setParameter($this, "ass_id", "0");
491 }
492
493 public function downloadSelectedObject(): void
494 {
495 if (count($this->selected_participants) > 0) {
496 $this->downloadSubmissionsObject($this->selected_participants);
497 } else {
498 $this->backToCurrentOverview();
499 }
500 }
501 public function downloadSubmissionsObject(?array $selected_participants = null): void
502 {
503 $participant_id = $this->requested_part_id;
504
505 $download_task = new ilDownloadSubmissionsBackgroundTask(
506 (int) $GLOBALS['DIC']->user()->getId(),
507 $this->exercise->getRefId(),
508 $this->exercise->getId(),
509 $this->ass_id,
510 $participant_id,
512 );
513
514 if ($download_task->run()) {
515 $this->tpl->setOnScreenMessage('success', $this->lng->txt('exc_down_files_started_bg'), true);
516 }
517
518 $this->backToCurrentOverview();
519 }
520
521 public function backToCurrentOverview(): void
522 {
523 if ($this->assignment !== null) {
524 $this->ctrl->redirect($this, "members");
525 } else {
526 $this->ctrl->redirect($this, "showParticipant");
527 }
528 }
529
533 public function membersApplyObject(): void
534 {
535 $this->saveStatusAllObject(null, false);
537 $this,
538 "members",
539 $this->exercise,
540 $this->assignment->getId(),
541 $this->feedback_gui
542 );
543 $exc_tab->resetOffset();
544 $exc_tab->writeFilterToSession();
545
546 $this->membersObject();
547 }
548
552 public function membersResetObject(): void
553 {
555 $this,
556 "members",
557 $this->exercise,
558 $this->assignment->getId(),
559 $this->feedback_gui
560 );
561 $exc_tab->resetOffset();
562 $exc_tab->resetFilter();
563
564 $this->membersObject();
565 }
566
567 public function saveGradesObject(): void
568 {
569 $ilCtrl = $this->ctrl;
571
572 foreach ($this->requested_learning_comments as $k => $v) {
573 $marks_obj = new ilLPMarks($this->exercise->getId(), (int) $k);
574 $marks_obj->setComment($v);
575 $marks_obj->update();
576 }
577 foreach ($this->requested_marks as $k => $v) {
578 $marks_obj = new ilLPMarks($this->exercise->getId(), (int) $k);
579 $marks_obj->setMark($v);
580 $marks_obj->update();
581 }
582 $this->tpl->setOnScreenMessage('success', $lng->txt("exc_msg_saved_grades"), true);
583 $ilCtrl->redirect($this, "showGradesOverview");
584 }
585
586
587 // TEXT ASSIGNMENT ?!
588
593 public function listTextAssignmentObject(): void
594 {
595 $this->initFilter();
596 $this->setBackToMembers();
597
599 $button_print = $this->ui_factory->button()->standard($this->lng->txt('print'), "#")
600 ->withOnLoadCode(function ($id) {
601 return "$('#$id').click(function() { window.print(); return false; });";
602 });
603 $this->toolbar->addSeparator();
604 $this->toolbar->addComponent($button_print);
605
606 $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "components/ILIAS/Exercise");
607 $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_list_text_assignment") . ": " . $this->assignment->getTitle());
608
609 $report_html = "";
610 $total_reports = 0;
611
612 $members = ilExSubmission::getAssignmentParticipants($this->exercise->getId(), $this->ass_id);
613 $members_filter = new ilExerciseMembersFilter($this->exercise->getRefId(), $members, $this->user->getId());
614 $members = $members_filter->filterParticipantsByAccess();
615
616 $sm = $this->domain->submission($this->assignment->getId());
617 foreach ($sm->getSubmissionsOfOwners($members) as $sub) {
618 if (trim($sub->getText()) && $this->domain->profile()->exists($sub->getUserId())) {
619 $feedback_data = $this->collectFeedbackDataFromPeer(
620 $sub->getUserId(),
621 $sub->getTimestamp(),
622 $sub->getText()
623 );
624 $submission_data = $this->assignment->getExerciseMemberAssignmentData($sub->getUserId(), $this->filter["status"] ?? "");
625
626 if (is_array($submission_data)) {
627 $data = array_merge($feedback_data, $submission_data);
628 $report_html .= $this->getReportPanel($data);
629 $total_reports++;
630 }
631 }
632 }
633 if ($total_reports == 0) {
634 $mess = $this->ui_factory->messageBox()->info($this->lng->txt("fiter_no_results"));
635 $report_html .= $this->ui_renderer->render($mess);
636 }
637
638 $group_panels_tpl->setVariable('CONTENT', $report_html);
639 $this->tpl->setContent($group_panels_tpl->get());
640 }
641
647 public function compareTextAssignmentsObject(): void
648 {
649 $this->setBackToMembers();
650 $subm = $this->domain->submission($this->assignment->getId());
651
652 $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "components/ILIAS/Exercise");
653 $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_compare_selected_submissions"));
654
655 $report_html = "";
656 //participant ids selected via checkboxes
657 $participants = array_keys($this->getMultiActionUserIds());
658
659 foreach ($participants as $participant_id) {
660 $subs = $subm->getSubmissionsOfUser($participant_id);
661 $ts = "";
662 $text = "";
663 if ($s = $subs->current()) {
664 $ts = $s->getTimestamp();
665 $text = $s->getText();
666 }
667
668 $feedback_data = $this->collectFeedbackDataFromPeer(
669 $participant_id,
670 $ts,
671 $text
672 );
673
674 $submission_data = $this->assignment->getExerciseMemberAssignmentData((int) $participant_id, $this->filter["status"] ?? "");
675
676 if (is_array($submission_data)) {
677 $data = array_merge($feedback_data, $submission_data);
678 $report_html .= $this->getReportPanel($data);
679 }
680 }
681
682 $group_panels_tpl->setVariable('CONTENT', $report_html);
683 $this->tpl->setContent($group_panels_tpl->get());
684 }
685
689 public function getReportPanel(array $a_data): string
690 {
691 $modal = $this->getEvaluationModal($a_data);
692
693 $this->ctrl->setParameter($this, "member_id", $a_data['uid']);
694 $actions = array(
695 $this->ui_factory->button()->shy($this->lng->txt("grade_evaluate"), "#")->withOnClick($modal->getShowSignal())
696 );
697
698 if ($this->exercise->hasTutorFeedbackMail()) {
699 $actions[] = $this->ui_factory->button()->shy(
700 $this->lng->txt("exc_tbl_action_feedback_mail"),
701 $this->ctrl->getLinkTarget($this, "redirectFeedbackMail")
702 );
703 }
704 if ($this->exercise->hasTutorFeedbackFile()) {
705 $actions[] = $this->ui_factory->button()->shy(
706 $this->lng->txt("exc_tbl_action_feedback_file"),
707 $this->ctrl->getLinkTargetByClass(ilResourceCollectionGUI::class)
708 );
709 }
710
711 $this->ctrl->setParameter($this, "member_id", "");
712
713 $actions_dropdown = $this->ui_factory->dropdown()->standard($actions);
714 if ($a_data['status'] == self::GRADE_NOT_GRADED) {
715 $str_status_key = $this->lng->txt('exc_tbl_status') . ": ";
716 $str_status_value = "-";
717 } else {
718 $str_status_key = $this->lng->txt('exc_tbl_status_time') . ": ";
719 $str_status_value = ilDatePresentation::formatDate(new ilDateTime($a_data["status_time"], IL_CAL_DATETIME));
720 }
721
722 $str_mark_key = $this->lng->txt("exc_tbl_mark") . ": ";
723 $str_mark_value = "-";
724
725 if (($a_data['mark'] != "")) {
726 $str_mark_value = $a_data['mark'];
727 }
728
729 if ($a_data['feedback_time']) {
730 $str_evaluation_key = $this->lng->txt('exc_tbl_feedback_time') . ": ";
731 $str_evaluation_value = ilDatePresentation::formatDate(new ilDateTime($a_data["feedback_time"], IL_CAL_DATETIME));
732 } else {
733 $str_evaluation_key = $this->lng->txt('exc_settings_feedback') . ": ";
734 $str_evaluation_value = "-";
735 }
736
737 $card_content = array(
738 $this->lng->txt("exc_tbl_submission_date") . ": " => ilDatePresentation::formatDate(new ilDateTime($a_data["udate"], IL_CAL_DATETIME)),
739 $str_status_key => $str_status_value,
740 $str_mark_key => $str_mark_value,
741 $str_evaluation_key => $str_evaluation_value,
742 $this->lng->txt('feedback_given') . ": " => $a_data['fb_given'],
743 $this->lng->txt('feedback_received') . ": " => $a_data['fb_received']
744 );
745 $card_tpl = new ilTemplate("tpl.exc_report_details_card.html", true, true, "components/ILIAS/Exercise");
746 foreach ($card_content as $key => $value) {
747 $card_tpl->setCurrentBlock("assingment_card");
748 $card_tpl->setVariable("ROW_KEY", $key);
749 $card_tpl->setVariable("ROW_VALUE", $value);
750 $card_tpl->parseCurrentBlock();
751 }
752
753 $main_panel = $this->ui_factory->panel()->sub($a_data['uname'], $this->ui_factory->legacy()->content(
754 $this->gui->html()->escapeCurly($a_data['utext'])
755 ))
756 ->withFurtherInformation($this->ui_factory->card()->standard($this->lng->txt('text_assignment'))->withSections(array($this->ui_factory->legacy()->content($card_tpl->get()))))->withActions($actions_dropdown);
757
758 $feedback_tpl = new ilTemplate("tpl.exc_report_feedback.html", true, true, "components/ILIAS/Exercise");
759 //if no feedback filter the feedback is displayed. Can be list submissions or compare submissions.
760 $filter_feedback = $this->filter["feedback"] ?? "";
761 if (array_key_exists("peer", $a_data) && (($filter_feedback == self::FEEDBACK_FULL_SUBMISSION) || $filter_feedback == "")) {
762 $feedback_tpl->setCurrentBlock("feedback");
763 foreach ($a_data["peer"] as $peer_id) {
764 if (ilObject::_lookupType($peer_id) == "usr") {
765 $user = new ilObjUser($peer_id);
766 $peer_name = $user->getFirstname() . " " . $user->getLastname();
767 } else {
768 $peer_name = $this->lng->txt("exc_deleted_user");
769 }
770
771 $feedback_tpl->setCurrentBlock("peer_feedback");
772 $feedback_tpl->setVariable("PEER_NAME", $peer_name);
773
774 $submission = new ilExSubmission($this->assignment, $a_data["uid"]);
775 $values = $submission->getPeerReview()->getPeerReviewValues($peer_id, $a_data["uid"]);
776
777 $review_html = "";
778 foreach ($this->assignment->getPeerReviewCriteriaCatalogueItems() as $crit) {
779 $crit_id = $crit->getId()
780 ? $crit->getId()
781 : $crit->getType();
782 $crit->setPeerReviewContext($this->assignment, $peer_id, $a_data["uid"]);
783
784 $review_html .=
785 '<div class="ilBlockPropertyCaption">' . $crit->getTitle() . '</div>' .
786 '<div style="margin:2px 0;">' . $crit->getHTML($values[$crit_id] ?? null) . '</div>';
787 }
788 $feedback_tpl->setVariable("PEER_FEEDBACK", $review_html);
789 $feedback_tpl->parseCurrentBlock();
790 }
791 $feedback_tpl->parseCurrentBlock();
792 }
793 $feedback_tpl->setVariable("GRADE", $this->lng->txt('exc_grading') . ": " . $this->lng->txt('exc_' . $a_data['status']));
794 $comment = ($a_data['comment'] === "")
795 ? "-"
796 : $a_data['comment'];
797 $feedback_tpl->setVariable("COMMENT", $this->lng->txt('exc_comment') . ": <br>" . $comment);
798
799 $feedback_panel = $this->ui_factory->panel()->sub("", $this->ui_factory->legacy()->content($feedback_tpl->get()));
800
801 $report = $this->ui_factory->panel()->report("", array($main_panel, $feedback_panel));
802
803 return $this->ui_renderer->render([$modal,$report]);
804 }
805
806 public function getEvaluationModal(
807 array $a_data
808 ): RoundTrip {
809 $more_id = $a_data['uid'];
810 $this->tpl->addJavaScript("assets/js/exc-text-more.js");
811 $modal_tpl = new ilTemplate("tpl.exc_report_evaluation_modal.html", true, true, "components/ILIAS/Exercise");
812 $modal_tpl->setVariable("USER_NAME", $a_data['uname']);
813
814 $form = $this->getEvaluationModalForm($a_data);
815 //TODO: CHECK ilias string utils. ilUtil shortenText with net blank.
816 if ($this->exercise->hasTutorFeedbackText()) {
817 $max_chars = 500;
818 $more_button = $this->gui->ui()->factory()->button()->standard($this->lng->txt("exc_show_more"), "#");
819 $text = "<div data-exc-show-more='$more_id'><div>";
820 $text .= $a_data["utext"];
821 $text .= "</div><div>";
822 $text .= $this->gui->ui()->renderer()->render($more_button);
823 $text .= "</div></div>";
824 $modal_tpl->setVariable("USER_TEXT", $text);
825 }
826
827 $modal_tpl->setVariable("FORM", $form->getHTML());
828
829 $form_id = 'form_' . $form->getId();
830 $submit_btn = $this->ui_factory->button()->primary($this->lng->txt("save"), '#')
831 ->withOnLoadCode(function ($id) use ($form_id) {
832 return "$('#$id').click(function() { $('#$form_id').submit(); return false; });";
833 });
834
835 return $this->ui_factory->modal()->roundtrip(strtoupper($this->lng->txt("grade_evaluate")), $this->ui_factory->legacy()->content($modal_tpl->get()))->withActionButtons([$submit_btn]);
836 }
837
838 public function getEvaluationModalForm(
839 array $a_data
841 $form = new ilPropertyFormGUI();
842 $this->ctrl->setParameterByClass(
843 self::class,
844 "ass_id",
845 $this->assignment->getId()
846 );
847 $form->setFormAction($this->ctrl->getFormAction($this, "saveEvaluationFromModal"));
848 $form->setId(uniqid('form'));
849
850 //Grade
851 $options = array(
852 self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
853 self::GRADE_PASSED => $this->lng->txt("exc_passed"),
854 self::GRADE_FAILED => $this->lng->txt("exc_failed")
855 );
856 $si = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "grade");
857 $si->setOptions($options);
858 $si->setValue($a_data['status'] ?? "");
859 $form->addItem($si);
860
861 //Mark
862 $mark_input = new ilTextInputGUI($this->lng->txt("exc_tbl_mark"), "mark");
863 $mark_input->setValue($a_data['mark'] ?? "");
864 $mark_input->setMaxLength(32);
865 $mark_input->setSize(4);
866 $form->addItem($mark_input);
867
868 $item = new ilHiddenInputGUI('mem_id');
869 $item->setValue($a_data['uid'] ?? "");
870 $form->addItem($item);
871
872 //TODO: CHECK ilias string utils. ilUtil shortenText with net blank.
873 if ($this->exercise->hasTutorFeedbackText()) {
874 $ta = new ilTextAreaInputGUI($this->lng->txt("exc_comment"), 'comment');
875 $ta->setInfo($this->lng->txt("exc_comment_for_learner_info"));
876 $ta->setValue($a_data['comment'] ?? "");
877 $ta->setRows(10);
878 $form->addItem($ta);
879 }
880 return $form;
881 }
882
883 // Save assignment submission grade(status) and comment from the roundtrip modal.
884
888 public function saveEvaluationFromModalObject(): void
889 {
890 $form = $this->getEvaluationModalForm([]);
891 $user_id = 0;
892 $comment = "";
893 $mark = "";
894 $grade = "";
895 if ($form->checkInput()) {
896 $comment = trim($form->getInput('comment'));
897 $user_id = (int) $form->getInput('mem_id');
898 $grade = trim($form->getInput('grade'));
899 $mark = trim($form->getInput('mark'));
900 }
901 if ($this->assignment->getId() && $user_id > 0) {
902 $member_status = $this->assignment->getMemberStatus($user_id);
903 $member_status->setComment(ilUtil::stripSlashes($comment));
904 if ($grade != "") {
905 $member_status->setStatus($grade);
906 }
907 $member_status->setMark($mark);
908 if ($comment != "") {
909 $member_status->setFeedback(true);
910 }
911 $member_status->update();
912 }
913 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_status_saved"), true);
914 $this->ctrl->redirect($this, "listTextAssignment");
915 }
916
917 // Add user as member
918
922 public function addUserFromAutoCompleteObject(): void
923 {
924 if ($this->requested_user_login == "") {
925 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('msg_no_search_string'));
926 $this->membersObject();
927 return;
928 }
929 $users = explode(',', $this->requested_user_login);
930
931 $user_ids = array();
932 foreach ($users as $user) {
934
935 if (!$user_id) {
936 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('user_not_known'));
937 $this->membersObject();
938 return;
939 }
940
941 $user_ids[] = $user_id;
942 }
943
944 $this->addMembersObject($user_ids);
945 }
946
947 // Add new partipant
948 public function addMembersObject($a_user_ids = array()): void
949 {
950 if (!count($a_user_ids)) {
951 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
952 } else {
953 if (!$this->exercise->members_obj->assignMembers($a_user_ids)) {
954 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("exc_members_already_assigned"), true);
955 } else {
956 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_members_assigned"), true);
957 }
958 }
959 $this->ctrl->redirect($this, "members");
960 }
961
965 public function selectAssignmentObject(): void
966 {
967 $ctrl = $this->ctrl;
968 $ctrl->setParameter($this, "ass_id", $this->requested_ass_id);
969 $ctrl->redirect($this, "members");
970 }
971
975 public function showParticipantObject(): void
976 {
977 $tpl = $this->tpl;
978 $ilToolbar = $this->toolbar;
979 $ilCtrl = $this->ctrl;
981 $access = $this->access;
982
983 $this->addSubTabs("participant");
984 $this->ctrl->setParameter($this, "ass_id", "0");
985
986 // participant selection
987 $members = $this->exercise->members_obj->getMembers();
988
990 'edit_submissions_grades',
991 'edit_submissions_grades',
992 $this->exercise->getRefId(),
993 $members
994 );
995
996
997 if (count($members) == 0) {
998 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_no_participants"));
999 return;
1000 }
1001
1002 $mems = array();
1003 foreach ($members as $mem_id) {
1004 if (ilObject::_lookupType($mem_id) == "usr") {
1005 $name = ilObjUser::_lookupName($mem_id);
1006 if (trim($name["login"]) != "") { // #20073
1007 $mems[$mem_id] = $name;
1008 }
1009 }
1010 }
1011
1012 $mems = ilArrayUtil::sortArray($mems, "lastname", "asc", false, true);
1013
1014 if ($this->requested_part_id == 0 && $mems !== [] && key($mems) > 0) {
1015 $ilCtrl->setParameter($this, "part_id", key($mems));
1016 $ilCtrl->redirect($this, "showParticipant");
1017 }
1018
1019 $current_participant = $this->requested_part_id;
1020
1021 reset($mems);
1022 if (count($mems) > 1) {
1023 $options = array();
1024 foreach ($mems as $k => $m) {
1025 $options[$k] =
1026 $m["lastname"] . ", " . $m["firstname"] . " [" . $m["login"] . "]";
1027 }
1028 $si = new ilSelectInputGUI($this->lng->txt("exc_participant"), "part_id");
1029 $si->setOptions($options);
1030 $si->setValue($current_participant);
1031 $ilToolbar->addStickyItem($si, true);
1032
1033 $this->gui->button(
1034 $this->lng->txt("select"),
1035 "selectParticipant"
1036 )->submit()->toToolbar(true);
1037 }
1038
1039 if ($mems !== []) {
1040 $this->ctrl->setParameter($this, "vw", self::VIEW_PARTICIPANT);
1041 $this->ctrl->setParameter($this, "part_id", $current_participant);
1042
1043 $ass = ilExAssignment::getInstancesByExercise($this->exercise->getId());
1044
1045 if (count($ass) > 0) {
1046 $ilToolbar->addSeparator();
1047 $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
1048 $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
1049 }
1050
1052 $this,
1053 "showParticipant",
1054 $this->exercise,
1055 $current_participant,
1056 $this->feedback_gui
1057 );
1058 $tpl->setContent($part_tab->getHTML() .
1059 $this->initIndividualDeadlineModal());
1060 } else {
1061 $this->tpl->setOnScreenMessage('info', $this->lng->txt("exc_no_assignments_available"));
1062 }
1063 }
1064
1067 public function showParticipantApplyObject(): void
1068 {
1070 $this,
1071 "showParticipant",
1072 $this->exercise,
1073 $this->requested_part_id,
1074 $this->feedback_gui
1075 );
1076 $exc_tab->resetOffset();
1077 $exc_tab->writeFilterToSession();
1078
1079 $this->showParticipantObject();
1080 }
1081
1084 public function showParticipantResetObject(): void
1085 {
1087 $this,
1088 "showParticipant",
1089 $this->exercise,
1090 $this->requested_part_id,
1091 $this->feedback_gui
1092 );
1093 $exc_tab->resetOffset();
1094 $exc_tab->resetFilter();
1095
1096 $this->showParticipantObject();
1097 }
1098
1102 public function selectParticipantObject(): void
1103 {
1104 $ctrl = $this->ctrl;
1105 $ctrl->setParameter($this, "part_id", $this->requested_part_id);
1106 $ctrl->redirect($this, "showParticipant");
1107 }
1108
1109 public function showGradesOverviewObject(): void
1110 {
1111 $tpl = $this->tpl;
1112 $ilToolbar = $this->toolbar;
1113 $ilCtrl = $this->ctrl;
1114 $lng = $this->lng;
1115
1116 $this->addSubTabs("grades");
1117
1118 $mem_obj = new ilExerciseMembers($this->exercise);
1119 $mems = $mem_obj->getMembers();
1120
1121 $mems = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1122 'edit_submissions_grades',
1123 'edit_submissions_grades',
1124 $this->exercise->getRefId(),
1125 $mems
1126 );
1127 if (count($mems) > 0) {
1128 $ilToolbar->addButton(
1129 $lng->txt("exc_export_excel"),
1130 $ilCtrl->getLinkTarget($this, "exportExcel")
1131 );
1132 }
1133
1134 $this->ctrl->setParameter($this, "vw", self::VIEW_GRADES);
1135
1136 $grades_tab = new ilExGradesTableGUI(
1137 $this,
1138 "showGradesOverview",
1139 $this->service,
1140 $mem_obj
1141 );
1142 $tpl->setContent($grades_tab->getHTML());
1143 }
1144
1148 public function redirectFeedbackMailObject(): void
1149 {
1150 if ($this->requested_member_id > 0) {
1151 $submission = new ilExSubmission($this->assignment, $this->requested_member_id);
1152 $members = $submission->getUserIds();
1153 } elseif ($members = $this->getMultiActionUserIds()) {
1154 $members = array_keys($members);
1155 }
1156
1157 if ($members !== []) {
1158 $logins = array();
1159 foreach ($members as $user_id) {
1160 $member_status = $this->assignment->getMemberStatus($user_id);
1161 $member_status->setFeedback(true);
1162 $member_status->update();
1163
1164 $logins[] = ilObjUser::_lookupLogin($user_id);
1165 }
1166 $logins = implode(",", $logins);
1167
1168 // #16530 - see ilObjCourseGUI::createMailSignature
1169 $sig = chr(13) . chr(10) . chr(13) . chr(10);
1170 $sig .= $this->lng->txt('exc_mail_permanent_link');
1171 $sig .= chr(13) . chr(10) . chr(13) . chr(10);
1172 $sig .= ilLink::_getLink($this->exercise->getRefId());
1173 $sig = rawurlencode(base64_encode($sig));
1174
1176 $this,
1177 $this->getViewBack(),
1178 array(),
1179 array(
1180 'type' => 'new',
1181 'rcp_to' => $logins,
1183 )
1184 ));
1185 }
1186 }
1187
1188 // Download all submitted files (of all members).
1189
1193 protected function getMultiActionUserIds(bool $a_keep_teams = false): array
1194 {
1195 $members = [];
1196 // multi-user
1197 if ($this->assignment !== null) {
1198 if (count($this->selected_participants) == 0) {
1199 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
1200 $this->ctrl->redirect($this, "members");
1201 }
1202
1203 foreach ($this->selected_participants as $user_id) {
1204 $submission = new ilExSubmission($this->assignment, $user_id);
1205 $tmembers = $submission->getUserIds();
1206 if (!$a_keep_teams) {
1207 foreach ($tmembers as $tuser_id) {
1208 $members[$tuser_id] = 1;
1209 }
1210 } else {
1211 if ($tmembers) {
1212 $members[] = $tmembers;
1213 } else {
1214 // no team yet
1215 $members[] = $user_id;
1216 }
1217 }
1218 }
1219 }
1220 // multi-ass
1221 else {
1222 if (count($this->selected_ass_ids) == 0) {
1223 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
1224 $this->ctrl->redirect($this, "showParticipant");
1225 }
1226
1227 $user_id = $this->requested_part_id;
1228
1229 foreach ($this->selected_ass_ids as $ass_id) {
1230 $submission = new ilExSubmission(new ilExAssignment($ass_id), $user_id);
1231 $tmembers = $submission->getUserIds();
1232 if (!$a_keep_teams) {
1233 foreach ($tmembers as $tuser_id) {
1234 $members[$ass_id][] = $tuser_id;
1235 }
1236 } else {
1237 if ($tmembers) {
1238 $members[$ass_id][] = $tmembers;
1239 } else {
1240 // no team yet
1241 $members[$ass_id][] = $user_id;
1242 }
1243 }
1244 }
1245 }
1246
1247 return $members;
1248 }
1249
1250 // Send assignment per mail to participants
1251
1255 public function sendMembersObject(): void
1256 {
1257 $members = $this->getMultiActionUserIds();
1258
1259 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_sent"), true);
1260 if ($this->assignment !== null) {
1261 $this->exercise->sendAssignment($this->assignment, array_keys($members));
1262 $this->ctrl->redirect($this, "members");
1263 } else {
1264 foreach ($members as $ass_id => $users) {
1265 $this->exercise->sendAssignment(new ilExAssignment($ass_id), $users);
1266 }
1267 $this->ctrl->setParameter($this, "part_id", $this->requested_part_id); // #17629
1268 $this->ctrl->redirect($this, "showParticipant");
1269 }
1270 }
1271
1275 public function confirmDeassignMembersObject(): void
1276 {
1277 $ilCtrl = $this->ctrl;
1278 $tpl = $this->tpl;
1279 $lng = $this->lng;
1280
1281 $members = $this->getMultiActionUserIds();
1282
1283 $cgui = new ilConfirmationGUI();
1284 $cgui->setFormAction($ilCtrl->getFormAction($this));
1285 $cgui->setHeaderText($lng->txt("exc_msg_sure_to_deassign_participant"));
1286 $cgui->setCancel($lng->txt("cancel"), "members");
1287 $cgui->setConfirm($lng->txt("remove"), "deassignMembers");
1288 foreach ($members as $k => $m) {
1289 $cgui->addItem(
1290 "member_ids[]",
1291 $k,
1292 ilUserUtil::getNamePresentation((int) $k, false, false, "", true)
1293 );
1294 }
1295
1296 $tpl->setContent($cgui->getHTML());
1297 }
1298
1299 // Deassign members from exercise
1300
1304 public function deassignMembersObject(): void
1305 {
1306 $ilCtrl = $this->ctrl;
1307 $lng = $this->lng;
1308
1309 $member_ids = $this->request->getMemberIds();
1310
1311 foreach ($member_ids as $usr_id) {
1312 $this->exercise->members_obj->deassignMember((int) $usr_id);
1313 }
1314 $this->tpl->setOnScreenMessage('success', $lng->txt("exc_msg_participants_removed"), true);
1315 $ilCtrl->redirect($this, "members");
1316 }
1317
1322 public function saveStatusParticipantObject(?array $selected_ass_ids = null): void
1323 {
1324 $ilCtrl = $this->ctrl;
1325
1326 $member_id = $this->requested_part_id;
1327 $data = array();
1328 $marks = $this->requested_marks;
1329 $status = $this->requested_status;
1330 $notices = $this->requested_tutor_notices;
1331 foreach ($this->listed_ass_ids as $ass_id) {
1332 if (is_array($selected_ass_ids) &&
1333 !in_array($ass_id, $selected_ass_ids)) {
1334 continue;
1335 }
1336
1337 $data[$ass_id][$member_id] = array(
1338 "status" => $status[$ass_id] ?? ""
1339 );
1340 if (isset($marks[$ass_id])) {
1341 $data[$ass_id][$member_id]["mark"] = $marks[$ass_id];
1342 }
1343 if (isset($notices[$ass_id])) {
1344 $data[$ass_id][$member_id]["notice"] = $notices[$ass_id];
1345 }
1346 }
1347
1348 $ilCtrl->setParameter($this, "part_id", $member_id); // #17629
1349 $this->saveStatus($data);
1350 }
1351
1355 public function saveStatusAllObject(
1356 ?array $a_selected = null,
1357 bool $a_redirect = true
1358 ): void {
1359 $user_ids = $this->listed_participants;
1360 $marks = $this->requested_marks;
1361 $notices = $this->requested_tutor_notices;
1362 $status = $this->requested_status;
1363 $filtered_user_ids = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1364 'edit_submissions_grades',
1365 'edit_submissions_grades',
1366 $this->exercise->getRefId(),
1367 $user_ids
1368 );
1369
1370 $data = array();
1371 foreach ($filtered_user_ids as $user_id) {
1372 if (is_array($a_selected) &&
1373 !in_array($user_id, $a_selected)) {
1374 continue;
1375 }
1376
1377 $data[-1][$user_id] = array(
1378 "status" => $status[$user_id] ?? null
1379 );
1380
1381 if (isset($marks[$user_id])) {
1382 $data[-1][$user_id]["mark"] = $marks[$user_id];
1383 }
1384 if (isset($notices[$user_id])) {
1385 $data[-1][$user_id]["notice"] = $notices[$user_id];
1386 }
1387 }
1388 $this->saveStatus($data, $a_redirect);
1389 }
1390
1394 public function saveStatusSelectedObject(): void
1395 {
1396 //$members = $this->getMultiActionUserIds();
1397 if ($this->assignment !== null) {
1398 $this->saveStatusAllObject($this->selected_participants);
1399 } else {
1400 $this->saveStatusParticipantObject($this->selected_ass_ids);
1401 }
1402 }
1403
1404 // Save status of selected members
1405
1409 protected function saveStatus(
1410 array $a_data,
1411 bool $a_redirect = true
1412 ): void {
1413 $ilCtrl = $this->ctrl;
1414 $saved_for = array();
1415 foreach ($a_data as $ass_id => $users) {
1416 $ass = ($ass_id < 0)
1417 ? $this->assignment
1418 : new ilExAssignment($ass_id);
1419 foreach ($users as $user_id => $values) {
1420 // this will add team members if available
1421 // $user_id is only the ID of one team member here,
1422 // $sub_user_id will be all team members
1423 $submission = new ilExSubmission($ass, $user_id);
1424 foreach ($submission->getUserIds() as $sub_user_id) {
1425 $uname = ilObjUser::_lookupName($sub_user_id);
1426 $saved_for[$sub_user_id] = $uname["lastname"] . ", " . $uname["firstname"];
1427
1428 $member_status = $ass->getMemberStatus($sub_user_id);
1429
1430 // see bug #22566
1431 $status = $values["status"];
1432 if ($status == "") {
1433 $status = self::GRADE_NOT_GRADED;
1434 }
1435 $member_status->setStatus($status);
1436 if (array_key_exists("mark", $values)) {
1437 $member_status->setMark($values["mark"]);
1438 }
1439 if (array_key_exists("notice", $values)) {
1440 $member_status->setNotice($values["notice"]);
1441 }
1442 $member_status->update();
1443 }
1444 }
1445 }
1446
1447 $save_for_str = "";
1448 if ($saved_for !== []) {
1449 $save_for_str = "(" . implode(" - ", $saved_for) . ")";
1450 }
1451
1452 if ($a_redirect) {
1453 $this->tpl->setOnScreenMessage('success', $this->lng->txt("exc_status_saved") . " " . $save_for_str, true);
1454 $ilCtrl->redirect($this, $this->getViewBack());
1455 }
1456 }
1457
1458 public function exportExcelObject(): void
1459 {
1460 $this->exercise->exportGradesExcel();
1461 exit;
1462 }
1463
1464
1465 //
1466 // TEAM
1467 //
1468
1472 public function createTeamsObject(): void
1473 {
1474 $ilCtrl = $this->ctrl;
1475
1476 $members = $this->getMultiActionUserIds(true);
1477
1478 $new_members = array();
1479
1480 foreach ($members as $group) {
1481 if (is_array($group)) {
1482 $new_members = array_merge($new_members, $group);
1483
1484 $first_user = $group;
1485 $first_user = array_shift($first_user);
1486 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1487 foreach ($group as $user_id) {
1488 $team->removeTeamMember($user_id);
1489 }
1490 } else {
1491 $new_members[] = $group;
1492 }
1493 }
1494
1495 if ($new_members !== []) {
1496 // see ilExSubmissionTeamGUI::addTeamMemberActionObject()
1497
1498 $first_user = array_shift($new_members);
1499 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user, true);
1500 foreach ($new_members as $user_id) {
1501 $team->addTeamMember($user_id);
1502 }
1503
1504 // re-evaluate complete team, as some members might have had submitted
1505 $submission = new ilExSubmission($this->assignment, $first_user);
1506 $this->exercise->processExerciseStatus(
1507 $this->assignment,
1508 $team->getMembers(),
1509 $submission->hasSubmitted(),
1510 $submission->validatePeerReviews()
1511 );
1512 }
1513
1514 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1515 $ilCtrl->redirect($this, "members");
1516 }
1517
1521 public function dissolveTeamsObject(): void
1522 {
1523 $ilCtrl = $this->ctrl;
1524
1525 $members = $this->getMultiActionUserIds(true);
1526
1527 foreach ($members as $group) {
1528 // if single member - nothing to do
1529 if (is_array($group)) {
1530 // see ilExSubmissionTeamGUI::removeTeamMemberObject()
1531
1532 $first_user = $group;
1533 $first_user = array_shift($first_user);
1534 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1535 foreach ($group as $user_id) {
1536 $team->removeTeamMember($user_id);
1537 }
1538
1539 // reset ex team members, as any submission is not valid without team
1540 $this->exercise->processExerciseStatus(
1541 $this->assignment,
1542 $group,
1543 false
1544 );
1545 }
1546 }
1547
1548 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1549 $ilCtrl->redirect($this, "members");
1550 }
1551
1553 ?ilPropertyFormGUI $a_form = null
1554 ): void {
1555 $ilCtrl = $this->ctrl;
1556 $ilTabs = $this->tabs_gui;
1557 $lng = $this->lng;
1558 $tpl = $this->tpl;
1559
1560 $ilTabs->clearTargets();
1561 $ilTabs->setBackTarget(
1562 $lng->txt("back"),
1563 $ilCtrl->getLinkTarget($this, $this->getViewBack())
1564 );
1565
1566 if ($a_form === null) {
1567 $a_form = $this->initGroupForm();
1568 }
1569 $tpl->setContent($a_form->getHTML());
1570 }
1571
1572 protected function initGroupForm(): ilPropertyFormGUI
1573 {
1574 $lng = $this->lng;
1575
1576 $form = new ilPropertyFormGUI();
1577 $form->setTitle($lng->txt("exc_adopt_group_teams") . " - " . $this->assignment->getTitle());
1578 $form->setFormAction($this->ctrl->getFormAction($this, "createTeamsFromGroups"));
1579
1580 $all_members = array();
1581 foreach (ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId()) as $grp_id => $group) {
1582 if (count($group["members"]) !== 0) {
1583 $grp_team = new ilCheckboxGroupInputGUI($lng->txt("obj_grp") . " \"" . $group["title"] . "\"", "grpt[" . $grp_id . "]");
1584 $grp_value = $options = array();
1585 foreach ($group["members"] as $user_id) {
1586 $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1587 $options[$user_id] = $user_name;
1588 if (!in_array($user_id, $all_members)) {
1589 $grp_value[] = $user_id;
1590 $all_members[] = $user_id;
1591 }
1592 }
1593 asort($options);
1594 foreach ($options as $user_id => $user_name) {
1595 $grp_team->addOption(new ilCheckboxOption($user_name, $user_id));
1596 }
1597 $grp_team->setValue($grp_value);
1598 } else {
1599 $grp_team = new ilNonEditableValueGUI($group["title"]);
1600 $grp_team->setValue($lng->txt("exc_adopt_group_teams_no_members"));
1601 }
1602 $form->addItem($grp_team);
1603 }
1604
1605 if ($all_members !== []) {
1606 $form->addCommandButton("createTeamsFromGroups", $lng->txt("save"));
1607 }
1608 $form->addCommandButton("members", $lng->txt("cancel"));
1609
1610 return $form;
1611 }
1612
1616 public function createTeamsFromGroupsObject(): void
1617 {
1618 $lng = $this->lng;
1619
1620 $req_members = $this->requested_group_members;
1621
1622 $form = $this->initGroupForm();
1623 if ($form->checkInput()) {
1624 $map = ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId());
1625 $all_members = $teams = array();
1626 $valid = true;
1627 foreach (array_keys($map) as $grp_id) {
1628 if (isset($req_members[$grp_id]) && is_array($req_members[$grp_id])) {
1629 $members = $req_members[$grp_id];
1630 $teams[] = $members;
1631 $invalid_team_members = array();
1632
1633 foreach ($members as $user_id) {
1634 if (!array_key_exists($user_id, $all_members)) {
1635 $all_members[$user_id] = $grp_id;
1636 } else {
1637 // user is selected in multiple groups
1638 $invalid_team_members[] = $user_id;
1639 }
1640 }
1641
1642 if ($invalid_team_members !== []) {
1643 $valid = false;
1644
1645 $alert = array();
1646 foreach ($invalid_team_members as $user_id) {
1647 $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1648 $grp_title = $map[$all_members[$user_id]]["title"];
1649 $alert[] = sprintf($lng->txt("exc_adopt_group_teams_conflict"), $user_name, $grp_title);
1650 }
1651 $input = $form->getItemByPostVar("grpt[" . $grp_id . "]");
1652 $input->setAlert(implode("<br/>", $alert));
1653 }
1654 }
1655 }
1656 if ($valid) {
1657 if ($teams !== []) {
1658 $existing_users = array_keys(ilExAssignmentTeam::getAssignmentTeamMap($this->assignment->getId()));
1659
1660 // create teams from group selections
1661 $sum = array("added" => 0, "blocked" => 0);
1662 foreach ($teams as $members) {
1663 foreach ($members as $user_id) {
1664 if (!$this->exercise->members_obj->isAssigned($user_id)) {
1665 $this->exercise->members_obj->assignMember($user_id);
1666 }
1667
1668 if (!in_array($user_id, $existing_users)) {
1669 $sum["added"]++;
1670 } else {
1671 $sum["blocked"]++;
1672 }
1673 }
1674
1675 $first = array_shift($members);
1676 $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first, true);
1677
1678 // getTeamId() does NOT send notification
1679 // $team->sendNotification($this->exercise->getRefId(), $first, "add");
1680
1681 foreach ($members as $user_id) {
1682 $team->addTeamMember($user_id);
1683 }
1684 }
1685
1686 $mess = array();
1687 if ($sum["added"] !== 0) {
1688 $mess[] = sprintf($lng->txt("exc_adopt_group_teams_added"), $sum["added"]);
1689 }
1690 if ($sum["blocked"] !== 0) {
1691 $mess[] = sprintf($lng->txt("exc_adopt_group_teams_blocked"), $sum["blocked"]);
1692 }
1693 if ($sum["added"] !== 0) {
1694 $this->tpl->setOnScreenMessage('success', implode(" ", $mess), true);
1695 } else {
1696 $this->tpl->setOnScreenMessage('failure', implode(" ", $mess), true);
1697 }
1698 }
1699 $this->ctrl->redirect($this, "members");
1700 } else {
1701 $this->tpl->setOnScreenMessage('failure', $lng->txt("form_input_not_valid"));
1702 }
1703 }
1704
1705 $form->setValuesByPost();
1706 $this->adoptTeamsFromGroupObject($form);
1707 }
1708
1709
1713
1714 public function getMultiFeedbackForm(int $a_ass_id): FormAdapterGUI
1715 {
1716 $lng = $this->lng;
1717
1718 $form = $this->gui->form([self::class], "uploadMultiFeedback")
1719 ->section("main", ilExAssignment::lookupTitle($a_ass_id))
1720 ->file(
1721 "mfzip",
1722 $lng->txt("exc_multi_feedback_file"),
1723 $this->handleMultiFeedbackUploadResult(...),
1724 "rc_id",
1725 "",
1726 1,
1727 ["application/zip"]
1728 );
1729 return $form;
1730 }
1731
1733 FileUpload $upload,
1734 UploadResult $result
1736 $feedback_zip = $this->domain->assignment()->tutorFeedbackZip();
1737 $rid = $feedback_zip->importFromUploadResult(
1738 $this->ass_id,
1739 $this->user->getId(),
1740 $result
1741 );
1742 return new \ILIAS\FileUpload\Handler\BasicHandlerResult(
1743 '',
1744 \ILIAS\FileUpload\Handler\HandlerResult::STATUS_OK,
1745 $rid,
1746 ''
1747 );
1748 }
1749
1750
1752 ?FormAdapterGUI $form = null
1753 ): void {
1754 $lng = $this->lng;
1755 $tpl = $this->tpl;
1756
1757 $this->tpl->setOnScreenMessage('info', $lng->txt("exc_multi_feedb_info"));
1758
1759 $this->addSubTabs("assignment");
1760
1761 // #13719
1762 $this->gui->button(
1763 $this->lng->txt("exc_download_zip_structure"),
1764 $this->ctrl->getLinkTarget($this, "downloadMultiFeedbackZip")
1765 )->toToolbar();
1766
1767 if ($form === null) {
1768 $form = $this->getMultiFeedbackForm($this->assignment->getId());
1769 }
1770
1771 $tpl->setContent($form->render());
1772 }
1773
1777 public function downloadMultiFeedbackZipObject(): void
1778 {
1779 $st_file = $this->domain->assignment()->tutorFeedbackZip()->getMultiFeedbackStructureFile(
1780 $this->assignment,
1781 $this->exercise
1782 );
1783 $this->gui->httpUtil()->deliverString(
1784 $st_file->content,
1785 $st_file->filename,
1786 "application/zip"
1787 );
1788 }
1789
1793 public function uploadMultiFeedbackObject(): void
1794 {
1795 // #11983
1796 $form = $this->getMultiFeedbackForm($this->assignment->getId());
1797 if ($form->isValid()) {
1798 $this->ctrl->redirect($this, "showMultiFeedbackConfirmationTable");
1799 }
1800
1801 $this->showMultiFeedbackObject($form);
1802 }
1803
1808 {
1809 $tpl = $this->tpl;
1810
1811 $this->addSubTabs("assignment");
1812
1813 $tab = new ilFeedbackConfirmationTable2GUI($this, "showMultiFeedbackConfirmationTable", $this->assignment);
1814 $tpl->setContent($tab->getHTML());
1815 }
1816
1820 public function cancelMultiFeedbackObject(): void
1821 {
1822 $this->ctrl->redirect($this, "members");
1823 }
1824
1828 public function saveMultiFeedbackObject(): void
1829 {
1830 $feedback_zip = $this->domain->assignment()->tutorFeedbackZip();
1831 $feedback_zip->saveMultiFeedbackFiles(
1832 $this->exercise,
1833 $this->assignment->getId(),
1834 $this->user->getId(),
1835 $this->requested_files
1836 );
1837
1838 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1839 $this->ctrl->redirect($this, "members");
1840 }
1841
1842
1843 //
1844 // individual deadlines
1845 //
1846
1847 protected function initIndividualDeadlineModal(): string
1848 {
1849 $lng = $this->lng;
1850 $tpl = $this->tpl;
1851
1852 // prepare modal
1853 $modal = $this->ui_factory->modal()->roundtrip(
1854 $lng->txt("exc_individual_deadline"),
1855 $this->ui_factory->legacy()->content('<div id="ilExcIDlBody"></div>')
1856 );
1857 $show = $modal->getShowSignal()->getId();
1858 $close = $modal->getCloseSignal()->getId();
1859
1860 $ajax_url = $this->ctrl->getLinkTarget($this, "handleIndividualDeadlineCalls", "", true, false);
1861
1862 $tpl->addJavaScript("assets/js/ilExcIDl.js", true, 3);
1863 $tpl->addOnLoadCode("il.ExcIDl.init('" . $ajax_url . "','" . $show . "','" . $close . "');");
1864
1866
1867 return $this->ui_renderer->render($modal);
1868 }
1869
1874 array $a_data
1875 ): array {
1876 if ($a_data) {
1877 $map = array();
1878 $ass_tmp = array();
1879 foreach ($a_data as $item) {
1880 $item = explode("_", $item);
1881 $ass_id = $item[0];
1882 $user_id = $item[1];
1883
1884 if (!array_key_exists($ass_id, $ass_tmp)) {
1885 if ($this->assignment &&
1886 $ass_id == $this->assignment->getId()) {
1887 $ass_tmp[$ass_id] = $this->assignment;
1888 } else {
1889 $ass_tmp[$ass_id] = new ilExAssignment($ass_id);
1890 }
1891 }
1892
1893 $map[$ass_id][] = $user_id;
1894 }
1895
1896 return array($map, $ass_tmp);
1897 }
1898 return [];
1899 }
1900
1905 protected function handleIndividualDeadlineCallsObject(): void
1906 {
1907 $tpl = $this->tpl;
1908
1909 $this->ctrl->saveParameter($this, "part_id");
1910
1911 // from request "dn", see ilExcIdl.js
1912 if ($this->done) {
1913 $this->tpl->setOnScreenMessage('success', $this->lng->txt("settings_saved"), true);
1914 $this->ctrl->redirect($this, $this->assignment !== null
1915 ? "members"
1916 : "showParticipant");
1917 }
1918
1919 // initial form call
1920 if ($this->requested_idl_id != "") {
1921 $tmp = $this->parseIndividualDeadlineData(explode(",", $this->requested_idl_id));
1922 if (is_array($tmp)) {
1923 $form = $this->initIndividualDeadlineForm($tmp[1], $tmp[0]);
1924 echo $form->getHTML() .
1925 $tpl->getOnLoadCodeForAsynch();
1926 }
1927 }
1928 // form "submit"
1929 else {
1930 $tmp = array();
1931 $post = $this->http->request()->getParsedBody();
1932 foreach (array_keys($post) as $id) {
1933 if (substr($id, 0, 3) == "dl_") {
1934 $tmp[] = substr($id, 3);
1935 }
1936 }
1937 $tmp = $this->parseIndividualDeadlineData($tmp);
1938 $ass_map = $tmp[1];
1939 $users = $tmp[0];
1940 unset($tmp);
1941
1942 $form = $this->initIndividualDeadlineForm($ass_map, $users);
1943 $res = array();
1944 if ($valid = $form->checkInput()) {
1945 foreach ($users as $ass_id => $users2) {
1946 $ass = $ass_map[$ass_id];
1947
1948 // :TODO: should individual deadlines BEFORE extended be possible?
1949 $dl = new ilDateTime($ass->getDeadline(), IL_CAL_UNIX);
1950
1951 foreach ($users2 as $user_id) {
1952 $date_field = $form->getItemByPostVar("dl_" . $ass_id . "_" . $user_id);
1953 if (ilDate::_before($date_field->getDate(), $dl)) {
1954 $date_field->setAlert(sprintf($this->lng->txt("exc_individual_deadline_before_global"), ilDatePresentation::formatDate($dl)));
1955 $valid = false;
1956 } else {
1957 $res[$ass_id][$user_id] = $date_field->getDate();
1958 }
1959 }
1960 }
1961 }
1962
1963 if (!$valid) {
1964 $form->setValuesByPost();
1965 echo $form->getHTML() .
1966 $tpl->getOnLoadCodeForAsynch();
1967 } else {
1968 foreach ($res as $ass_id => $users) {
1969 $ass = $ass_map[$ass_id];
1970
1971 foreach ($users as $id => $date) {
1972 $ass->setIndividualDeadline($id, $date);
1973 if (is_numeric($id)) {
1974 $this->notification->sendDeadlineSetNotification($ass_id, $id);
1975 }
1976 }
1977
1978 $subm = $this->domain->submission($ass->getId());
1979 $subm->recalculateLateSubmissions();
1980 }
1981
1982 echo "ok";
1983 }
1984 }
1985
1986 exit();
1987 }
1988
1992 protected function initIndividualDeadlineForm(
1993 array $a_ass_map,
1994 array $ids
1996 $form = new ilPropertyFormGUI();
1997 $form->setFormAction($this->ctrl->getFormAction($this));
1998 $form->setName("ilExcIDlForm");
1999
2000 foreach ($ids as $ass_id => $users) {
2001 $ass = $a_ass_map[$ass_id];
2002
2003 $section = new ilFormSectionHeaderGUI();
2004 $section->setTitle($ass->getTitle());
2005 $form->addItem($section);
2006
2007 $teams = ilExAssignmentTeam::getInstancesFromMap($ass->getId());
2008
2009 $values = $ass->getIndividualDeadlines();
2010
2011 foreach ($users as $id) {
2012 // single user
2013 if (is_numeric($id)) {
2014 $name = ilObjUser::_lookupName($id);
2015 $name = $name["lastname"] . ", " . $name["firstname"];
2016 }
2017 // team
2018 else {
2019 $name = "";
2020 $team_id = (int) substr($id, 1);
2021 if (array_key_exists($team_id, $teams)) {
2022 $name = array();
2023 foreach ($teams[$team_id]->getMembers() as $member_id) {
2024 $uname = ilObjUser::_lookupName($member_id);
2025 $name[] = $uname["lastname"] . ", " . $uname["firstname"];
2026 }
2027 asort($name);
2028 $name = implode("<br />", $name);
2029 }
2030 }
2031
2032 $dl = new ilDateTimeInputGUI($name, "dl_" . $ass_id . "_" . $id);
2033 $dl->setShowTime(true);
2034 $dl->setRequired(true);
2035 $form->addItem($dl);
2036
2037 if (array_key_exists($id, $values)) {
2038 $dl->setDate(new ilDateTime($values[$id], IL_CAL_UNIX));
2039 }
2040 }
2041 }
2042
2043 $form->addCommandButton("", $this->lng->txt("save"));
2044
2045 return $form;
2046 }
2047
2051 protected function setIndividualDeadlineObject(): void
2052 {
2053 // this will only get called if no selection
2054 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("select_one"));
2055
2056 if ($this->assignment !== null) {
2057 $this->membersObject();
2058 } else {
2059 $this->showParticipantObject();
2060 }
2061 }
2062
2063 public function initFilter(): void
2064 {
2065 if ($this->requested_filter_status != "") {
2066 $this->filter["status"] = $this->requested_filter_status;
2067 }
2068
2069 $this->lng->loadLanguageModule("search");
2070
2071 $this->toolbar->setFormAction($this->ctrl->getFormAction($this, "listTextAssignment"));
2072
2073 // Status
2074
2075 $si_status = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "filter_status");
2076 $options = array(
2077 "" => $this->lng->txt("search_any"),
2078 self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
2079 self::GRADE_PASSED => $this->lng->txt("exc_passed"),
2080 self::GRADE_FAILED => $this->lng->txt("exc_failed")
2081 );
2082 $si_status->setOptions($options);
2083 $si_status->setValue($this->filter["status"] ?? "");
2084
2085 $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2086 $options = array(
2087 self::FEEDBACK_FULL_SUBMISSION => $this->lng->txt("submissions_feedback"),
2088 self::FEEDBACK_ONLY_SUBMISSION => $this->lng->txt("submissions_only")
2089 );
2090 $si_feedback->setOptions($options);
2091 $si_feedback->setValue($this->filter["feedback"] ?? "");
2092
2093 $this->toolbar->addInputItem($si_status, true);
2094
2095 // Submissions and Feedback
2096 #24713
2097 if ($this->assignment->getPeerReview()) {
2098 if ($this->requested_filter_feedback != "") {
2099 $this->filter["feedback"] = $this->requested_filter_feedback;
2100 } else {
2101 $this->filter["feedback"] = "submission_feedback";
2102 }
2103
2104 $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2105 $options = array(
2106 "submission_feedback" => $this->lng->txt("submissions_feedback"),
2107 "submission_only" => $this->lng->txt("submissions_only")
2108 );
2109 $si_feedback->setOptions($options);
2110 $si_feedback->setValue($this->filter["feedback"] ?? "");
2111
2112 $this->toolbar->addInputItem($si_feedback, true);
2113 }
2114
2115 $this->gui->button(
2116 $this->lng->txt("filter"),
2117 "listTextAssignment"
2118 )->submit()->toToolbar();
2119 }
2120
2124 public function openSubmissionPrintViewObject(): void
2125 {
2126 $this->openSubmissionViewObject(true);
2127 }
2128
2132 public function openSubmissionViewObject(bool $print_version = false): void
2133 {
2134 global $DIC;
2135
2136 $member_id = $this->requested_member_id;
2137
2138 $submission = new ilExSubmission($this->assignment, $member_id);
2139 $entry = $submission->getSubmittedEntry($print_version);
2140 if (is_null($entry)) {
2141 throw new ilExerciseException("No submission entry for " . $this->assignment->getId() . " / " .
2142 $member_id . ".");
2143 }
2144 $rid = $entry->getRid();
2145
2146 $last_opening = $submission->getLastOpeningHTMLView();
2147 $submission_time = $submission->getLastSubmission();
2148
2149 if ($rid !== "") {
2150 $zip_internal_path = "ilExercise/" . \ilFileSystemAbstractionStorage::createPathFromId(
2151 $this->assignment->getExerciseId(),
2152 "exc"
2153 ) . "/subm_" . $this->assignment->getId() . "/" . $member_id . "/resource.zip";
2154 $obj_id = str_replace([".zip", "print"], "", $entry->getTitle());
2155 $obj_id = $this->assignment->getAssignmentType()->getExportObjIdForResourceId($obj_id);
2156 }
2157 if ($print_version) {
2158 $obj_id .= "print";
2159 }
2160
2161 $obj_dir = $this->assignment->getAssignmentType()->getStringIdentifier() . "_" . $obj_id;
2162
2163 $index_html_file =
2165 DIRECTORY_SEPARATOR .
2166 CLIENT_ID .
2167 DIRECTORY_SEPARATOR .
2168 dirname($zip_internal_path) .
2169 //DIRECTORY_SEPARATOR .
2170 //$obj_dir .
2171 DIRECTORY_SEPARATOR .
2172 "index.html";
2173 $this->log->debug("index html file: " . $index_html_file);
2174
2175 $web_filesystem = $DIC->filesystem()->web();
2176 if ($last_opening > $submission_time && $web_filesystem->has($index_html_file)) {
2178 ilUtil::redirect($index_html_file);
2179 }
2180 $error_msg = "";
2181 if ($rid !== "") {
2182 $file_copied = $this->domain->submission($this->ass_id)->copyRidToWebDir($rid, $zip_internal_path);
2183 }
2184
2185 // e.g. data/ilias/ilExercise/3/exc_327/subm_9/2/20231212085734_167.zip ?
2186 if ($file_copied) {
2187 $this->zip->unzipFile($file_copied);
2188 $web_filesystem->delete($zip_internal_path);
2189 $this->log->debug("deleting: " . $zip_internal_path);
2190
2191 $submission_repository = $this->service->repo()->submission();
2192 $submission_repository->updateWebDirAccessTime($this->assignment->getId(), $member_id);
2194 ilUtil::redirect($index_html_file . "?" . time());
2195 }
2196
2197 $error_msg = $this->lng->txt("exc_copy_zip_error");
2198
2199 if ($error_msg === '' || $error_msg === '0') {
2200 $error_msg = $this->lng->txt("exc_find_zip_error");
2201 }
2202
2203 $this->tpl->setOnScreenMessage('failure', $error_msg);
2204 }
2205
2210 string $external_file_path
2211 ): string {
2212 list($external_path, $internal_file_path) = explode(CLIENT_ID . "/ilExercise", $external_file_path);
2213 $internal_file_path = "ilExercise" . $internal_file_path;
2214 return $internal_file_path;
2215 }
2216
2217 /*
2218 * Add the Back link to the tabs. (used in submission list and submission compare)
2219 */
2220 protected function setBackToMembers(): void
2221 {
2222 //tabs
2223 $this->tabs_gui->clearTargets();
2224 $this->tabs_gui->setBackTarget(
2225 $this->lng->txt("back"),
2226 $this->ctrl->getLinkTarget($this, "members")
2227 );
2228 }
2229
2231 int $user_id,
2232 string $ts,
2233 string $text
2234 ): array {
2235 $user = new ilObjUser($user_id);
2236 $uname = $user->getFirstname() . " " . $user->getLastname();
2237
2238 $data = array(
2239 "uid" => $user_id,
2240 "uname" => $uname,
2241 "udate" => $ts,
2242 "utext" => $this->gui->getUIUtil()->formatTextInput($text) // mob id to mob src
2243 );
2244
2245 //get data peer and assign it
2246 $peer_review = new ilExPeerReview($this->assignment);
2247 $data["peer"] = array();
2248 foreach ($peer_review->getPeerReviewsByPeerId($user_id) as $value) {
2249 $data["peer"][] = $value['giver_id'];
2250 }
2251
2252 $data["fb_received"] = count($data["peer"]);
2253 $data["fb_given"] = $peer_review->countGivenFeedback(true, $user_id);
2254
2255 return $data;
2256 }
2257
2258 public function sendGradingNotificationObject(): void
2259 {
2260
2261 $ass_id = $this->request->getAssId();
2262 $selected_users = $this->request->getSelectedParticipants();
2263
2264 $graded_users = array_filter($selected_users, function ($user_id) {
2265 return $this->assignment->getMemberStatus($user_id)->getStatus() !== "notgraded";
2266 });
2267
2268 if (count($graded_users) === 0) {
2269 $this->tpl->setOnScreenMessage("failure", $this->lng->txt("exc_no_graded_mem_selected"), true);
2270 $this->ctrl->redirect($this, $this->getViewBack());
2271 }
2272
2273 $not = new ilExerciseMailNotification();
2275 $not->setAssignmentId($ass_id);
2276 $not->setObjId($this->exercise->getId());
2277 $not->setRefId($this->exercise->getRefId());
2278 $not->setRecipients($graded_users);
2279 $not->send();
2280 $this->tpl->setOnScreenMessage("success", $this->lng->txt("exc_graded_mem_notified"), true);
2281 $this->ctrl->redirect($this, $this->getViewBack());
2282 }
2283
2284 protected function setFailedObject(): void
2285 {
2286 $members = $this->getMultiActionUserIds();
2287 $done = false;
2288 if ($this->assignment !== null) {
2289 foreach (array_keys($members) as $mem) {
2290 $done = true;
2291 $this->setSingleStatus($this->assignment->getId(), $mem, "failed");
2292 }
2293 if ($done) {
2294 $this->tpl->setOnScreenMessage("success", $this->lng->txt("msg_obj_modified"), true);
2295 }
2296 }
2297 $this->ctrl->redirect($this, "members");
2298 }
2299
2300 protected function setPassedObject(): void
2301 {
2302 $members = $this->getMultiActionUserIds();
2303 $done = false;
2304 if ($this->assignment !== null) {
2305 foreach (array_keys($members) as $mem) {
2306 $done = true;
2307 $this->setSingleStatus($this->assignment->getId(), $mem, "passed");
2308 }
2309 if ($done) {
2310 $this->tpl->setOnScreenMessage("success", $this->lng->txt("msg_obj_modified"), true);
2311 }
2312 }
2313 $this->ctrl->redirect($this, "members");
2314 }
2315
2316 protected function setSingleStatus($ass_id, $part_id, $status): void
2317 {
2318 $ass = new ilExAssignment($ass_id);
2319 $submission = new ilExSubmission($ass, $part_id);
2320 $member_status = $ass->getMemberStatus($part_id);
2321 $member_status->setStatus($status);
2322 $member_status->update();
2323 }
2324}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$comment
Definition: buildRTE.php:72
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
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 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, array $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:70
$GLOBALS["DIC"]
Definition: wac.php:54
$text
Definition: xapiexit.php:21