ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilExerciseManagementGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
16 {
20  protected $ctrl;
21 
25  protected $tabs_gui;
26 
30  protected $lng;
31 
35  protected $tpl;
36 
40  protected $ui_factory;
41 
45  protected $ui_renderer;
46 
50  protected $filter;
51 
55  protected $toolbar;
56 
57  protected $exercise; // [ilObjExercise]
58  protected $assignment; // [ilExAssignment]
59 
63  protected $task_factory;
64 
68  protected $log;
69 
73  protected $user;
74 
75  const VIEW_ASSIGNMENT = 1;
76  const VIEW_PARTICIPANT = 2;
77  const VIEW_GRADES = 3;
78 
79  const FEEDBACK_ONLY_SUBMISSION = "submission_only";
80  const FEEDBACK_FULL_SUBMISSION = "submission_feedback";
81 
82  const GRADE_NOT_GRADED = "notgraded";
83  const GRADE_PASSED = "passed";
84  const GRADE_FAILED = "failed";
85 
89  protected $service;
90 
98  {
99  global $DIC;
100 
101  $this->ui_factory = $DIC->ui()->factory();
102  $this->ui_renderer = $DIC->ui()->renderer();
103  $this->user = $DIC->user();
104  $this->toolbar = $DIC->toolbar();
105  $this->log = ilLoggerFactory::getLogger("exc");
106 
107  $this->ctrl = $DIC->ctrl();
108  $this->tabs_gui = $DIC->tabs();
109  $this->lng = $DIC->language();
110  $this->tpl = $DIC["tpl"];
111 
112  $this->task_factory = $DIC->backgroundTasks()->taskFactory();
113 
114  $request = $DIC->exercise()->internal()->request();
115 
116  $this->service = $service;
117 
118  $this->exercise = $request->getRequestedExercise();
119  if ($a_ass) {
120  $this->assignment = $a_ass;
121  $this->ass_id = $this->assignment->getId();
122  }
123 
124  $this->ctrl->saveParameter($this, array("vw", "member_id"));
125  $this->ctrl->saveParameter($this, array("part_id"));
126  }
127 
128  public function executeCommand()
129  {
130  $ilCtrl = $this->ctrl;
131  $lng = $this->lng;
132  $ilTabs = $this->tabs_gui;
133 
134  $class = $ilCtrl->getNextClass($this);
135  //$cmd = $ilCtrl->getCmd("listPublicSubmissions");
136 
137  switch ($class) {
138  case "ilfilesystemgui":
139  $ilTabs->clearTargets();
140  $ilTabs->setBackTarget(
141  $lng->txt("back"),
142  $ilCtrl->getLinkTarget($this, $this->getViewBack())
143  );
144 
145  ilUtil::sendInfo($lng->txt("exc_fb_tutor_info"));
146 
147  $fstorage = new ilFSStorageExercise($this->exercise->getId(), $this->assignment->getId());
148  $fstorage->create();
149 
150  $submission = new ilExSubmission($this->assignment, (int) $_GET["member_id"]);
151  $feedback_id = $submission->getFeedbackId();
152  $noti_rec_ids = $submission->getUserIds();
153 
154  $fs_title = array();
155  foreach ($noti_rec_ids as $rec_id) {
156  $fs_title[] = ilUserUtil::getNamePresentation($rec_id, false, false, "", true);
157  }
158  $fs_title = implode(" / ", $fs_title);
159 
160  $fs_gui = new ilFileSystemGUI($fstorage->getFeedbackPath($feedback_id));
161  $fs_gui->setTableId("excfbfil" . $this->assignment->getId() . "_" . $feedback_id);
162  $fs_gui->setAllowDirectories(false);
163  $fs_gui->setTitle($lng->txt("exc_fb_files") . " - " .
164  $this->assignment->getTitle() . " - " .
165  $fs_title);
166  $pcommand = $fs_gui->getLastPerformedCommand();
167  if (is_array($pcommand) && $pcommand["cmd"] == "create_file") {
168  foreach ($noti_rec_ids as $user_id) {
169  $member_status = $this->assignment->getMemberStatus($user_id);
170  $member_status->setFeedback(true);
171  $member_status->update();
172  }
173 
174  $this->exercise->sendFeedbackFileNotification(
175  $pcommand["name"],
176  $noti_rec_ids,
177  $this->assignment->getId()
178  );
179  }
180  $this->ctrl->forwardCommand($fs_gui);
181  break;
182 
183  case 'ilrepositorysearchgui':
184  $rep_search = new ilRepositorySearchGUI();
185  $ref_id = $this->exercise->getRefId();
186  $rep_search->addUserAccessFilterCallable(function ($a_user_ids) use ($ref_id) {
187  return $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
188  'edit_submissions_grades',
189  'edit_submissions_grades',
190  $ref_id,
191  $a_user_ids
192  );
193  });
194  $rep_search->setTitle($this->lng->txt("exc_add_participant"));
195  $rep_search->setCallback($this, 'addMembersObject');
196 
197  // Set tabs
198  $this->addSubTabs("assignment");
199  $this->ctrl->setReturn($this, 'members');
200 
201  $this->ctrl->forwardCommand($rep_search);
202  break;
203 
204  case "ilexsubmissionteamgui":
205  $gui = new ilExSubmissionTeamGUI($this->exercise, $this->initSubmission());
206  $ilCtrl->forwardCommand($gui);
207  break;
208 
209  case "ilexsubmissionfilegui":
210  $gui = new ilExSubmissionFileGUI($this->exercise, $this->initSubmission());
211  $ilCtrl->forwardCommand($gui);
212  break;
213 
214  case "ilexsubmissiontextgui":
215  $ilCtrl->saveParameter($this, array("part_id"));
216  $gui = new ilExSubmissionTextGUI($this->exercise, $this->initSubmission());
217  $ilCtrl->forwardCommand($gui);
218  break;
219 
220  case "ilexpeerreviewgui":
221  $gui = new ilExPeerReviewGUI($this->assignment, $this->initSubmission());
222  $ilCtrl->forwardCommand($gui);
223  break;
224 
225  default:
226  $cmd = $ilCtrl->getCmd();
227  switch ($cmd) {
228  case 'downloadSubmissions':
229  $cmd = $ilCtrl->getCmd("downloadSubmissions");
230  break;
231  default:
232  $cmd = $ilCtrl->getCmd("listPublicSubmissions");
233  break;
234  }
235  $this->{$cmd . "Object"}();
236  break;
237  }
238  }
239 
240  protected function getViewBack()
241  {
242  switch ($_REQUEST["vw"]) {
243  case self::VIEW_PARTICIPANT:
244  $back_cmd = "showParticipant";
245  break;
246 
247  case self::VIEW_GRADES:
248  $back_cmd = "showGradesOverview";
249  break;
250 
251  default:
252  // case self::VIEW_ASSIGNMENT:
253  $back_cmd = "members";
254  break;
255  }
256  return $back_cmd;
257  }
258 
259  protected function initSubmission()
260  {
261  $back_cmd = $this->getViewBack();
262  $this->ctrl->setReturn($this, $back_cmd);
263 
264  $this->tabs_gui->clearTargets();
265  $this->tabs_gui->setBackTarget(
266  $this->lng->txt("back"),
267  $this->ctrl->getLinkTarget($this, $back_cmd)
268  );
269 
270  return new ilExSubmission($this->assignment, $_REQUEST["member_id"], null, true);
271  }
272 
278  public function addSubTabs($a_activate)
279  {
280  $ilTabs = $this->tabs_gui;
281  $lng = $this->lng;
282  $ilCtrl = $this->ctrl;
283 
284  $ass_id = $_GET["ass_id"];
285  $part_id = $_GET["part_id"];
286 
287  $ilCtrl->setParameter($this, "vw", "");
288  $ilCtrl->setParameter($this, "member_id", "");
289  $ilCtrl->setParameter($this, "ass_id", "");
290  $ilCtrl->setParameter($this, "part_id", "");
291 
292  $ilTabs->addSubTab(
293  "assignment",
294  $lng->txt("exc_assignment_view"),
295  $ilCtrl->getLinkTarget($this, "members")
296  );
297  $ilTabs->addSubTab(
298  "participant",
299  $lng->txt("exc_participant_view"),
300  $ilCtrl->getLinkTarget($this, "showParticipant")
301  );
302  $ilTabs->addSubTab(
303  "grades",
304  $lng->txt("exc_grades_overview"),
305  $ilCtrl->getLinkTarget($this, "showGradesOverview")
306  );
307  $ilTabs->activateSubTab($a_activate);
308 
309  $ilCtrl->setParameter($this, "ass_id", $ass_id);
310  $ilCtrl->setParameter($this, "part_id", $part_id);
311  }
312 
313  public function waitingDownloadObject()
314  {
315  $lng = $this->lng;
316  $ilCtrl = $this->ctrl;
317 
318  $ilCtrl->setParameterByClass("ilExSubmissionFileGUI", "member_id", (int) $_GET["member_id"]);
319  $url = $ilCtrl->getLinkTargetByClass(array("ilRepositoryGUI", "ilExerciseHandlerGUI", "ilObjExerciseGUI", "ilExerciseManagementGUI", "ilExSubmissionFileGUI"), "downloadNewReturned");
320  $js_url = $ilCtrl->getLinkTargetByClass(array("ilRepositoryGUI", "ilExerciseHandlerGUI", "ilObjExerciseGUI", "ilExerciseManagementGUI", "ilExSubmissionFileGUI"), "downloadNewReturned", "", "", false);
321  ilUtil::sendInfo($lng->txt("exc_wait_for_files") . "<a href='$url'> " . $lng->txt('exc_download_files') . "</a><script>window.location.href ='" . $js_url . "';</script>");
322  $this->membersObject();
323  }
324 
328  public function membersObject()
329  {
330  $tpl = $this->tpl;
331  $ilToolbar = $this->toolbar;
332  $ilCtrl = $this->ctrl;
333  $lng = $this->lng;
334 
335  $this->addSubTabs("assignment");
336 
337  // assignment selection
338  $ass = ilExAssignment::getInstancesByExercise($this->exercise->getId());
339 
340  if (!$this->assignment) {
341  $this->assignment = current($ass);
342  }
343 
344  reset($ass);
345  if (count($ass) > 1) {
346  $options = array();
347  foreach ($ass as $a) {
348  $options[$a->getId()] = $a->getTitle();
349  }
350  $si = new ilSelectInputGUI($this->lng->txt("exc_assignment"), "ass_id");
351  $si->setOptions($options);
352  $si->setValue($this->assignment->getId());
353  $ilToolbar->addStickyItem($si, true);
354 
355  $button = ilSubmitButton::getInstance();
356  $button->setCaption("select");
357  $button->setCommand("selectAssignment");
358  $ilToolbar->addStickyItem($button);
359 
360  $ilToolbar->addSeparator();
361  }
362  // #16165 - if only 1 assignment dropdown is not displayed;
363  elseif ($this->assignment) {
364  $ilCtrl->setParameter($this, "ass_id", $this->assignment->getId());
365  }
366 
367  // add member
368  // is only shown if 'edit_submissions_grades' is granted by rbac. positions
369  // access is not sufficient.
370  $has_rbac_access = $GLOBALS['DIC']->access()->checkAccess(
371  'edit_submissions_grades',
372  '',
373  $this->exercise->getRefId()
374  );
375  if ($has_rbac_access) {
377  $this,
378  $ilToolbar,
379  array(
380  'auto_complete_name' => $lng->txt('user'),
381  'submit_name' => $lng->txt('add'),
382  'add_search' => true,
383  'add_from_container' => $this->exercise->getRefId()
384  )
385  );
386  }
387 
388  // #16168 - no assignments
389  if (count($ass) > 0) {
390  if ($has_rbac_access) {
391  $ilToolbar->addSeparator();
392  }
393 
394  // we do not want the ilRepositorySearchGUI form action
395  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
396 
397  $ilCtrl->setParameter($this, "ass_id", $this->assignment->getId());
398 
399  if ($this->assignment->getType() == ilExAssignment::TYPE_UPLOAD_TEAM) {
400  if (ilExAssignmentTeam::getAdoptableGroups($this->exercise->getRefId())) {
401  $ilToolbar->addButton(
402  $this->lng->txt("exc_adopt_group_teams"),
403  $this->ctrl->getLinkTarget($this, "adoptTeamsFromGroup")
404  );
405 
406  $ilToolbar->addSeparator();
407  }
408  } elseif ($this->exercise->hasTutorFeedbackFile()) {
409  if (!$this->assignment->getAssignmentType()->usesTeams()) {
410  // multi-feedback
411  $ilToolbar->addButton(
412  $this->lng->txt("exc_multi_feedback"),
413  $this->ctrl->getLinkTarget($this, "showMultiFeedback")
414  );
415 
416  $ilToolbar->addSeparator();
417  }
418  }
419 
420  $submission_repository = new ilExcSubmissionRepository($this->db);
421 
422  if ($submission_repository->hasSubmissions($this->assignment->getId())) {
423  $ass_type = $this->assignment->getType();
424  //todo change addFormButton for addButtonInstance
425  if ($ass_type == ilExAssignment::TYPE_TEXT) {
426  $ilToolbar->addFormButton($lng->txt("exc_list_text_assignment"), "listTextAssignment");
427  }
428  $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
429  }
430  $this->ctrl->setParameter($this, "vw", self::VIEW_ASSIGNMENT);
431 
432  $exc_tab = new ilExerciseMemberTableGUI($this, "members", $this->exercise, $this->assignment->getId());
433  $tpl->setContent(
434  $exc_tab->getHTML() .
436  );
437  } else {
438  ilUtil::sendInfo($lng->txt("exc_no_assignments_available"));
439  }
440 
441  $ilCtrl->setParameter($this, "ass_id", "");
442 
443  return;
444  }
445 
446  public function downloadSubmissionsObject()
447  {
448  $participant_id = $_REQUEST['part_id'];
449 
450  $download_task = new ilDownloadSubmissionsBackgroundTask(
451  (int) $GLOBALS['DIC']->user()->getId(),
452  (int) $this->exercise->getRefId(),
453  (int) $this->exercise->getId(),
454  (int) $this->ass_id,
455  (int) $participant_id
456  );
457 
458  if ($download_task->run()) {
459  ilUtil::sendSuccess($this->lng->txt('exc_down_files_started_bg'), true);
460  }
461 
462  if ($this->assignment) {
463  $this->ctrl->redirect($this, "members");
464  } else {
465  $this->ctrl->redirect($this, "showParticipant");
466  }
467  }
468 
469  public function membersApplyObject()
470  {
471  $this->saveStatusAllObject(null, false);
472  $exc_tab = new ilExerciseMemberTableGUI($this, "members", $this->exercise, $this->assignment->getId());
473  $exc_tab->resetOffset();
474  $exc_tab->writeFilterToSession();
475 
476  $this->membersObject();
477  }
478 
479  public function membersResetObject()
480  {
481  $exc_tab = new ilExerciseMemberTableGUI($this, "members", $this->exercise, $this->assignment->getId());
482  $exc_tab->resetOffset();
483  $exc_tab->resetFilter();
484 
485  $this->membersObject();
486  }
487 
491  public function saveGradesObject()
492  {
493  $ilCtrl = $this->ctrl;
494  $lng = $this->lng;
495 
496  if (is_array($_POST["lcomment"])) {
497  foreach ($_POST["lcomment"] as $k => $v) {
498  $marks_obj = new ilLPMarks($this->exercise->getId(), (int) $k);
499  $marks_obj->setComment(ilUtil::stripSlashes($v));
500  $marks_obj->setMark(ilUtil::stripSlashes($_POST["mark"][$k]));
501  $marks_obj->update();
502  }
503  }
504  ilUtil::sendSuccess($lng->txt("exc_msg_saved_grades"), true);
505  $ilCtrl->redirect($this, "showGradesOverview");
506  }
507 
508 
509  // TEXT ASSIGNMENT ?!
510 
514  public function listTextAssignmentObject()
515  {
516  $this->initFilter();
517 
518  $this->setBackToMembers();
519 
520  $button_print = $this->ui_factory->button()->standard($this->lng->txt('print'), "#")
521  ->withOnLoadCode(function ($id) {
522  return "$('#{$id}').click(function() { window.print(); return false; });";
523  });
524  $this->toolbar->addSeparator();
525  $this->toolbar->addComponent($button_print);
526 
527  $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "Modules/Exercise");
528  $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_list_text_assignment") . ": " . $this->assignment->getTitle());
529 
530  $report_html = "";
531  $total_reports = 0;
532 
533  $members = ilExSubmission::getAssignmentParticipants($this->exercise->getId(), $this->ass_id);
534  $members_filter = new ilExerciseMembersFilter($this->exercise->getRefId(), $members, $this->user->getId());
535  $members = $members_filter->filterParticipantsByAccess();
536 
537  foreach (ilExSubmission::getAssignmentFilesByUsers($this->exercise->getId(), $this->assignment->getId(), $members) as $file) {
538  if (trim($file["atext"]) && ilObjUser::_exists($file["user_id"])) {
539  $feedback_data = $this->collectFeedbackDataFromPeer($file);
540  $submission_data = $this->assignment->getExerciseMemberAssignmentData($file["user_id"], $this->filter["status"]);
541 
542  if (is_array($submission_data)) {
543  $data = array_merge($feedback_data, $submission_data);
544  $report_html .= $this->getReportPanel($data);
545  $total_reports++;
546  }
547  }
548  }
549  if ($total_reports == 0) {
550  $mtpl = new ilTemplate("tpl.message.html", true, true, "Services/Utilities");
551  $mtpl->setCurrentBlock("info_message");
552  $mtpl->setVariable("TEXT", $this->lng->txt("fiter_no_results"));
553  $mtpl->parseCurrentBlock();
554  $report_html .= $mtpl->get();
555  }
556 
557  $group_panels_tpl->setVariable('CONTENT', $report_html);
558  $this->tpl->setContent($group_panels_tpl->get());
559  }
560 
567  {
568  $this->setBackToMembers();
569 
570  $group_panels_tpl = new ilTemplate("tpl.exc_group_report_panels.html", true, true, "Modules/Exercise");
571  $group_panels_tpl->setVariable('TITLE', $this->lng->txt("exc_compare_selected_submissions"));
572 
573  $report_html = "";
574  //participant ids selected via checkboxes
575  $participants = array_keys($this->getMultiActionUserIds());
576 
577  foreach ($participants as $participant_id) {
578  $submission = new ilExSubmission($this->assignment, $participant_id);
579 
580  //submission data array
581  $file = reset($submission->getFiles());
582 
583  if (!$file) {
584  $file = [
585  "user_id" => $participant_id,
586  "ts" => null,
587  "atext" => null
588  ];
589  }
590 
591  $feedback_data = $this->collectFeedbackDataFromPeer($file);
592 
593  $submission_data = $this->assignment->getExerciseMemberAssignmentData($file["user_id"], $this->filter["status"]);
594 
595  if (is_array($submission_data)) {
596  $data = array_merge($feedback_data, $submission_data);
597  $report_html .= $this->getReportPanel($data);
598  $total_reports++;
599  }
600  }
601 
602  $group_panels_tpl->setVariable('CONTENT', $report_html);
603  $this->tpl->setContent($group_panels_tpl->get());
604  }
605 
606  public function getReportPanel($a_data)
607  {
608  $modal = $this->getEvaluationModal($a_data);
609 
610  $this->ctrl->setParameter($this, "member_id", $a_data['uid']);
611  $actions = array(
612  $this->ui_factory->button()->shy($this->lng->txt("grade_evaluate"), "#")->withOnClick($modal->getShowSignal())
613  );
614 
615  if ($this->exercise->hasTutorFeedbackMail()) {
616  $actions[] = $this->ui_factory->button()->shy(
617  $this->lng->txt("exc_tbl_action_feedback_mail"),
618  $this->ctrl->getLinkTarget($this, "redirectFeedbackMail")
619  );
620  }
621  if ($this->exercise->hasTutorFeedbackFile()) {
622  $actions[] = $this->ui_factory->button()->shy(
623  $this->lng->txt("exc_tbl_action_feedback_file"),
624  $this->ctrl->getLinkTargetByClass("ilFileSystemGUI", "listFiles")
625  );
626  }
627 
628  $this->ctrl->setParameter($this, "member_id", "");
629 
630  $actions_dropdown = $this->ui_factory->dropdown()->standard($actions);
631 
632  if ($a_data['status'] == self::GRADE_NOT_GRADED) {
633  $str_status_key = $this->lng->txt('exc_tbl_status');
634  $str_status_value = $this->lng->txt('not_yet');
635  } else {
636  $str_status_key = $this->lng->txt('exc_tbl_status_time');
637  $str_status_value = ilDatePresentation::formatDate(new ilDateTime($a_data["status_time"], IL_CAL_DATETIME));
638  }
639 
640  $str_mark_key = $this->lng->txt("exc_tbl_mark");
641  $str_mark_value = $this->lng->txt('not_yet');
642 
643  if (($a_data['mark'] != "")) {
644  $str_mark_value = $a_data['mark'];
645  }
646 
647  if ($a_data['feedback_time']) {
648  $str_evaluation_key = $this->lng->txt('exc_tbl_feedback_time');
649  $str_evaluation_value = ilDatePresentation::formatDate(new ilDateTime($a_data["feedback_time"], IL_CAL_DATETIME));
650  } else {
651  $str_evaluation_key = $this->lng->txt('exc_settings_feedback');
652  $str_evaluation_value = $this->lng->txt('not_yet');
653  }
654 
655  $card_content = array(
656  $this->lng->txt("exc_tbl_submission_date") => ilDatePresentation::formatDate(new ilDateTime($a_data["udate"], IL_CAL_DATETIME)),
657  $str_status_key => $str_status_value,
658  $str_mark_key => $str_mark_value,
659  $str_evaluation_key => $str_evaluation_value,
660  $this->lng->txt('feedback_given') => $a_data['fb_given'],
661  $this->lng->txt('feedback_received') => $a_data['fb_received']
662  );
663  $card_tpl = new ilTemplate("tpl.exc_report_details_card.html", true, true, "Modules/Exercise");
664  foreach ($card_content as $key => $value) {
665  $card_tpl->setCurrentBlock("assingment_card");
666  $card_tpl->setVariable("ROW_KEY", $key);
667  $card_tpl->setVariable("ROW_VALUE", $value);
668  $card_tpl->parseCurrentBlock();
669  }
670 
671  $main_panel = $this->ui_factory->panel()->sub($a_data['uname'], $this->ui_factory->legacy($a_data['utext']))
672  ->withCard($this->ui_factory->card()->standard($this->lng->txt('text_assignment'))->withSections(array($this->ui_factory->legacy($card_tpl->get()))))->withActions($actions_dropdown);
673 
674  $feedback_tpl = new ilTemplate("tpl.exc_report_feedback.html", true, true, "Modules/Exercise");
675  //if no feedback filter the feedback is displayed. Can be list submissions or compare submissions.
676  if (array_key_exists("peer", $a_data) && ($this->filter["feedback"] == self::FEEDBACK_FULL_SUBMISSION) || $this->filter["feedback"] == "") {
677  $feedback_tpl->setCurrentBlock("feedback");
678  foreach ($a_data["peer"] as $peer_id) {
679  if (ilObject::_lookupType($peer_id) == "usr") {
680  $user = new ilObjUser($peer_id);
681  $peer_name = $user->getFirstname() . " " . $user->getLastname();
682  } else {
683  $peer_name = $this->lng->txt("exc_deleted_user");
684  }
685 
686  $feedback_tpl->setCurrentBlock("peer_feedback");
687  $feedback_tpl->setVariable("PEER_NAME", $peer_name);
688 
689  $submission = new ilExSubmission($this->assignment, $a_data["uid"]);
690  $values = $submission->getPeerReview()->getPeerReviewValues($peer_id, $a_data["uid"]);
691 
692  $review_html = "";
693  foreach ($this->assignment->getPeerReviewCriteriaCatalogueItems() as $crit) {
694  $crit_id = $crit->getId()
695  ? $crit->getId()
696  : $crit->getType();
697  $crit->setPeerReviewContext($this->assignment, $peer_id, $a_data["uid"]);
698 
699  $review_html .=
700  '<div class="ilBlockPropertyCaption">' . $crit->getTitle() . '</div>' .
701  '<div style="margin:2px 0;">' . $crit->getHTML($values[$crit_id]) . '</div>';
702  }
703  $feedback_tpl->setVariable("PEER_FEEDBACK", $review_html);
704  $feedback_tpl->parseCurrentBlock();
705  }
706  $feedback_tpl->parseCurrentBlock();
707  }
708  $feedback_tpl->setVariable("GRADE", $this->lng->txt('grade') . ": " . $this->lng->txt('exc_' . $a_data['status']));
709  $feedback_tpl->setVariable("COMMENT", $this->lng->txt('exc_comment') . "<br>" . $a_data['comment']);
710 
711  $feedback_panel = $this->ui_factory->panel()->sub("", $this->ui_factory->legacy($feedback_tpl->get()));
712 
713  $report = $this->ui_factory->panel()->report("", array($main_panel, $feedback_panel));
714 
715  return $this->ui_renderer->render([$modal,$report]);
716  }
717 
718  public function getEvaluationModal($a_data)
719  {
720  $modal_tpl = new ilTemplate("tpl.exc_report_evaluation_modal.html", true, true, "Modules/Exercise");
721  $modal_tpl->setVariable("USER_NAME", $a_data['uname']);
722 
723  $form = new ilPropertyFormGUI();
724  $form->setFormAction($this->ctrl->getFormAction($this, "saveEvaluationFromModal"));
725  $form->setId(uniqid('form'));
726 
727  //Grade
728  $options = array(
729  self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
730  self::GRADE_PASSED => $this->lng->txt("exc_passed"),
731  self::GRADE_FAILED => $this->lng->txt("exc_failed")
732  );
733  $si = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "grade");
734  $si->setOptions($options);
735  $si->setValue($a_data['status']);
736  $form->addItem($si);
737 
738  //Mark
739  $mark_input = new ilTextInputGUI($this->lng->txt("exc_tbl_mark"), "mark");
740  $mark_input->setValue($a_data['mark']);
741  $mark_input->setMaxLength(32);
742  $mark_input->setSize(4);
743  $form->addItem($mark_input);
744 
745  $item = new ilHiddenInputGUI('mem_id');
746  $item->setValue($a_data['uid']);
747  $form->addItem($item);
748 
749  //TODO: CHECK ilias string utils. ilUtil shortenText with net blank.
750  if ($this->exercise->hasTutorFeedbackText()) {
751  $max_chars = 500;
752 
753  $u_text = strip_tags($a_data["utext"]); //otherwise will get open P
754  $text = $u_text;
755  //show more
756  if (strlen($u_text) > $max_chars) {
757  $text = "<input type='checkbox' class='read-more-state' id='post-1' />";
758  $text .= "<div class='read-more-wrap'>";
759  $text .= mb_substr($u_text, 0, $max_chars);
760  $text .= "<span class='read-more-target'>";
761  $text .= mb_substr($u_text, $max_chars);
762  $text .= "</span></div>";
763  $text .= "<label for='post-1' class='read-more-trigger'></label>";
764  }
765  $modal_tpl->setVariable("USER_TEXT", $text);
766 
767  $ta = new ilTextAreaInputGUI($this->lng->txt("exc_comment"), 'comment');
768  $ta->setInfo($this->lng->txt("exc_comment_for_learner_info"));
769  $ta->setValue($a_data['comment']);
770  $ta->setRows(10);
771  $form->addItem($ta);
772  }
773 
774  $modal_tpl->setVariable("FORM", $form->getHTML());
775 
776  $form_id = 'form_' . $form->getId();
777  $submit_btn = $this->ui_factory->button()->primary($this->lng->txt("save"), '#')
778  ->withOnLoadCode(function ($id) use ($form_id) {
779  return "$('#{$id}').click(function() { $('#{$form_id}').submit(); return false; });";
780  });
781 
782  return $this->ui_factory->modal()->roundtrip(strtoupper($this->lng->txt("grade_evaluate")), $this->ui_factory->legacy($modal_tpl->get()))->withActionButtons([$submit_btn]);
783  }
784 
789  {
790  $comment = trim($_POST['comment']);
791  $user_id = (int) $_POST['mem_id'];
792  $grade = trim($_POST["grade"]);
793  $mark = trim($_POST['mark']);
794 
795  if ($this->assignment->getId() && $user_id) {
796  $member_status = $this->assignment->getMemberStatus($user_id);
797  $member_status->setComment(ilUtil::stripSlashes($comment));
798  $member_status->setStatus($grade);
799  $member_status->setMark($mark);
800  if ($comment != "") {
801  $member_status->setFeedback(true);
802  }
803  $member_status->update();
804  }
805  ilUtil::sendSuccess($this->lng->txt("exc_status_saved"), true);
806  $this->ctrl->redirect($this, "listTextAssignment");
807  }
808 
813  {
814  if (!strlen(trim($_POST['user_login']))) {
815  ilUtil::sendFailure($this->lng->txt('msg_no_search_string'));
816  $this->membersObject();
817  return false;
818  }
819  $users = explode(',', $_POST['user_login']);
820 
821  $user_ids = array();
822  foreach ($users as $user) {
823  $user_id = ilObjUser::_lookupId($user);
824 
825  if (!$user_id) {
826  ilUtil::sendFailure($this->lng->txt('user_not_known'));
827  return $this->membersObject();
828  }
829 
830  $user_ids[] = $user_id;
831  }
832 
833  if (!$this->addMembersObject($user_ids)) {
834  $this->membersObject();
835  return false;
836  }
837  return true;
838  }
839 
843  public function addMembersObject($a_user_ids = array())
844  {
845  if (!count($a_user_ids)) {
846  ilUtil::sendFailure($this->lng->txt("no_checkbox"));
847  return false;
848  }
849 
850  if (!$this->exercise->members_obj->assignMembers($a_user_ids)) {
851  ilUtil::sendFailure($this->lng->txt("exc_members_already_assigned"));
852  return false;
853  } else {
854  /* #16921
855  // #9946 - create team for new user(s) for each team upload assignment
856  foreach(ilExAssignment::getInstancesByExercise($this->exercise->getId()) as $ass)
857  {
858  if($ass->hasTeam())
859  {
860  foreach($a_user_ids as $user_id)
861  {
862  // #15915
863  ilExAssignmentTeam::getTeamId($ass->getId(), $user_id, true);
864  }
865  }
866  }
867  */
868 
869  ilUtil::sendSuccess($this->lng->txt("exc_members_assigned"), true);
870  }
871 
872  $this->ctrl->redirect($this, "members");
873  return true;
874  }
875 
876 
880  public function selectAssignmentObject()
881  {
882  $_GET["ass_id"] = ilUtil::stripSlashes($_POST["ass_id"]);
883  $this->membersObject();
884  }
885 
889  public function showParticipantObject()
890  {
891  $tpl = $this->tpl;
892  $ilToolbar = $this->toolbar;
893  $ilCtrl = $this->ctrl;
894  $lng = $this->lng;
895 
896  $this->addSubTabs("participant");
897  $this->ctrl->setParameter($this, "ass_id", "");
898 
899  // participant selection
900  $ass = ilExAssignment::getAssignmentDataOfExercise($this->exercise->getId());
901  $members = $this->exercise->members_obj->getMembers();
902 
903  $members = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
904  'edit_submissions_grades',
905  'edit_submissions_grades',
906  $this->exercise->getRefId(),
907  $members
908  );
909 
910 
911  if (count($members) == 0) {
912  ilUtil::sendInfo($lng->txt("exc_no_participants"));
913  return;
914  }
915 
916  $mems = array();
917  foreach ($members as $mem_id) {
918  if (ilObject::_lookupType($mem_id) == "usr") {
919  $name = ilObjUser::_lookupName($mem_id);
920  if (trim($name["login"]) != "") { // #20073
921  $mems[$mem_id] = $name;
922  }
923  }
924  }
925 
926  $mems = ilUtil::sortArray($mems, "lastname", "asc", false, true);
927 
928  if ($_GET["part_id"] == "" && count($mems) > 0) {
929  $_GET["part_id"] = key($mems);
930  }
931 
932  $current_participant = $_GET["part_id"];
933 
934  reset($mems);
935  if (count($mems) > 1) {
936  $options = array();
937  foreach ($mems as $k => $m) {
938  $options[$k] =
939  $m["lastname"] . ", " . $m["firstname"] . " [" . $m["login"] . "]";
940  }
941  $si = new ilSelectInputGUI($this->lng->txt("exc_participant"), "part_id");
942  $si->setOptions($options);
943  $si->setValue($current_participant);
944  $ilToolbar->addStickyItem($si, true);
945 
946  $button = ilSubmitButton::getInstance();
947  $button->setCaption("select");
948  $button->setCommand("selectParticipant");
949  $ilToolbar->addStickyItem($button);
950  }
951 
952  if (count($mems) > 0) {
953  $this->ctrl->setParameter($this, "vw", self::VIEW_PARTICIPANT);
954  $this->ctrl->setParameter($this, "part_id", $current_participant);
955 
956  $ilToolbar->addSeparator();
957  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
958  $ilToolbar->addFormButton($lng->txt("download_all_returned_files"), "downloadSubmissions");
959 
960  $part_tab = new ilExParticipantTableGUI(
961  $this,
962  "showParticipant",
963  $this->exercise,
964  $current_participant
965  );
966  $tpl->setContent($part_tab->getHTML() .
967  $this->initIndividualDeadlineModal());
968  } else {
969  ilUtil::sendInfo($this->lng->txt("exc_no_assignments_available"));
970  }
971  }
972 
973  public function showParticipantApplyObject()
974  {
975  $exc_tab = new ilExParticipantTableGUI($this, "showParticipant", $this->exercise, $_GET["part_id"]);
976  $exc_tab->resetOffset();
977  $exc_tab->writeFilterToSession();
978 
979  $this->showParticipantObject();
980  }
981 
982  public function showParticipantResetObject()
983  {
984  $exc_tab = new ilExParticipantTableGUI($this, "showParticipant", $this->exercise, $_GET["part_id"]);
985  $exc_tab->resetOffset();
986  $exc_tab->resetFilter();
987 
988  $this->showParticipantObject();
989  }
990 
994  public function selectParticipantObject()
995  {
996  $_GET["part_id"] = ilUtil::stripSlashes($_POST["part_id"]);
997  $this->showParticipantObject();
998  }
999 
1003  public function showGradesOverviewObject()
1004  {
1005  $tpl = $this->tpl;
1006  $ilToolbar = $this->toolbar;
1007  $ilCtrl = $this->ctrl;
1008  $lng = $this->lng;
1009 
1010  $this->addSubTabs("grades");
1011 
1012  $mem_obj = new ilExerciseMembers($this->exercise);
1013  $mems = $mem_obj->getMembers();
1014 
1015  $mems = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1016  'edit_submissions_grades',
1017  'edit_submissions_grades',
1018  $this->exercise->getRefId(),
1019  $mems
1020  );
1021  if (count($mems) > 0) {
1022  $ilToolbar->addButton(
1023  $lng->txt("exc_export_excel"),
1024  $ilCtrl->getLinkTarget($this, "exportExcel")
1025  );
1026  }
1027 
1028  $this->ctrl->setParameter($this, "vw", self::VIEW_GRADES);
1029 
1030  $grades_tab = new ilExGradesTableGUI(
1031  $this,
1032  "showGradesOverview",
1033  $this->service,
1034  $mem_obj
1035  );
1036  $tpl->setContent($grades_tab->getHTML());
1037  }
1038 
1042  public function redirectFeedbackMailObject()
1043  {
1044  $members = array();
1045 
1046  if ($_GET["member_id"] != "") {
1047  $submission = new ilExSubmission($this->assignment, $_GET["member_id"]);
1048  $members = $submission->getUserIds();
1049  } elseif ($members = $this->getMultiActionUserIds()) {
1050  $members = array_keys($members);
1051  }
1052 
1053  if ($members) {
1054  $logins = array();
1055  foreach ($members as $user_id) {
1056  $member_status = $this->assignment->getMemberStatus($user_id);
1057  $member_status->setFeedback(true);
1058  $member_status->update();
1059 
1060  $logins[] = ilObjUser::_lookupLogin($user_id);
1061  }
1062  $logins = implode(",", $logins);
1063 
1064  // #16530 - see ilObjCourseGUI::createMailSignature
1065  $sig = chr(13) . chr(10) . chr(13) . chr(10);
1066  $sig .= $this->lng->txt('exc_mail_permanent_link');
1067  $sig .= chr(13) . chr(10) . chr(13) . chr(10);
1068  $sig .= ilLink::_getLink($this->exercise->getRefId());
1069  $sig = rawurlencode(base64_encode($sig));
1070 
1072  $this,
1073  $this->getViewBack(),
1074  array(),
1075  array(
1076  'type' => 'new',
1077  'rcp_to' => $logins,
1079  )
1080  ));
1081  }
1082  }
1083 
1087  public function downloadAllObject()
1088  {
1089  $members = array();
1090 
1091  foreach ($this->exercise->members_obj->getMembers() as $member_id) {
1092  $submission = new ilExSubmission($this->assignment, $member_id);
1093  $submission->updateTutorDownloadTime();
1094 
1095  // get member object (ilObjUser)
1096  if (ilObject::_exists($member_id)) {
1097  $storage_id = "";
1098  // adding file metadata
1099  foreach ($submission->getFiles() as $file) {
1100  if ($this->assignment->getAssignmentType()->isSubmissionAssignedToTeam()) {
1101  $storage_id = $file["team_id"];
1102  } else {
1103  $storage_id = $file["user_id"];
1104  }
1105 
1106  $members[$storage_id]["files"][$file["returned_id"]] = $file;
1107  }
1108  if ($this->assignment->getAssignmentType()->isSubmissionAssignedToTeam()) {
1109  $name = "Team " . $submission->getTeam()->getId();
1110  } else {
1111  $tmp_obj = ilObjectFactory::getInstanceByObjId($member_id);
1112  $name = $tmp_obj->getFirstname() . " " . $tmp_obj->getLastname();
1113  }
1114  if ($storage_id > 0) {
1115  $members[$storage_id]["name"] = $name;
1116  }
1117  unset($tmp_obj);
1118  }
1119  }
1120 
1121  ilExSubmission::downloadAllAssignmentFiles($this->assignment, $members);
1122  }
1123 
1124  protected function getMultiActionUserIds($a_keep_teams = false)
1125  {
1126  // multi-user
1127  if ($this->assignment) {
1128  if (!$_POST["member"]) {
1129  ilUtil::sendFailure($this->lng->txt("no_checkbox"), true);
1130  $this->ctrl->redirect($this, "members");
1131  }
1132 
1133  foreach (array_keys($_POST["member"]) as $user_id) {
1134  $submission = new ilExSubmission($this->assignment, $user_id);
1135  $tmembers = $submission->getUserIds();
1136  if (!(bool) $a_keep_teams) {
1137  foreach ($tmembers as $tuser_id) {
1138  $members[$tuser_id] = 1;
1139  }
1140  } else {
1141  if ($tmembers) {
1142  $members[] = $tmembers;
1143  } else {
1144  // no team yet
1145  $members[] = $user_id;
1146  }
1147  }
1148  }
1149  }
1150  // multi-ass
1151  else {
1152  if (!$_POST["ass"]) {
1153  ilUtil::sendFailure($this->lng->txt("no_checkbox"), true);
1154  $this->ctrl->redirect($this, "showParticipant");
1155  }
1156 
1157  $user_id = $_GET["part_id"];
1158 
1159  foreach (array_keys($_POST["ass"]) as $ass_id) {
1160  $submission = new ilExSubmission(new ilExAssignment($ass_id), $user_id);
1161  $tmembers = $submission->getUserIds();
1162  if (!(bool) $a_keep_teams) {
1163  foreach ($tmembers as $tuser_id) {
1164  $members[$ass_id][] = $tuser_id;
1165  }
1166  } else {
1167  if ($tmembers) {
1168  $members[$ass_id][] = $tmembers;
1169  } else {
1170  // no team yet
1171  $members[$ass_id][] = $user_id;
1172  }
1173  }
1174  }
1175  }
1176 
1177  return $members;
1178  }
1179 
1183  public function sendMembersObject()
1184  {
1185  $members = $this->getMultiActionUserIds();
1186 
1187  ilUtil::sendSuccess($this->lng->txt("exc_sent"), true);
1188  if ($this->assignment) {
1189  $this->exercise->sendAssignment($this->assignment, array_keys($members));
1190  $this->ctrl->redirect($this, "members");
1191  } else {
1192  foreach ($members as $ass_id => $users) {
1193  $this->exercise->sendAssignment(new ilExAssignment($ass_id), $users);
1194  }
1195  $this->ctrl->setParameter($this, "part_id", $_GET["part_id"]); // #17629
1196  $this->ctrl->redirect($this, "showParticipant");
1197  }
1198  }
1199 
1204  {
1205  $ilCtrl = $this->ctrl;
1206  $tpl = $this->tpl;
1207  $lng = $this->lng;
1208 
1209  $members = $this->getMultiActionUserIds();
1210 
1211  $cgui = new ilConfirmationGUI();
1212  $cgui->setFormAction($ilCtrl->getFormAction($this));
1213  $cgui->setHeaderText($lng->txt("exc_msg_sure_to_deassign_participant"));
1214  $cgui->setCancel($lng->txt("cancel"), "members");
1215  $cgui->setConfirm($lng->txt("remove"), "deassignMembers");
1216 
1217  foreach ($members as $k => $m) {
1218  $cgui->addItem(
1219  "member[$k]",
1220  $m,
1221  ilUserUtil::getNamePresentation((int) $k, false, false, "", true)
1222  );
1223  }
1224 
1225  $tpl->setContent($cgui->getHTML());
1226  }
1227 
1231  public function deassignMembersObject()
1232  {
1233  $ilCtrl = $this->ctrl;
1234  $lng = $this->lng;
1235 
1236  $members = $this->getMultiActionUserIds();
1237 
1238  foreach (array_keys($members) as $usr_id) {
1239  $this->exercise->members_obj->deassignMember((int) $usr_id);
1240  $this->removeUserSubmissionFilesFromWebDir((int) $usr_id);
1241  }
1242  ilUtil::sendSuccess($lng->txt("exc_msg_participants_removed"), true);
1243  $ilCtrl->redirect($this, "members");
1244  }
1245 
1246  public function removeUserSubmissionFilesFromWebDir(int $user_id) : void
1247  {
1248  $storage = new ilFSWebStorageExercise($this->exercise->getId(), $this->ass_id);
1249  $storage->deleteUserSubmissionDirectory($user_id);
1250  }
1251 
1252  public function saveCommentsObject()
1253  {
1254  if (!isset($_POST['comments_value'])) {
1255  return;
1256  }
1257 
1258  $this->exercise->members_obj->setNoticeForMember(
1259  $_GET["member_id"],
1260  ilUtil::stripSlashes($_POST["comments_value"])
1261  );
1262  ilUtil::sendSuccess($this->lng->txt("exc_members_comments_saved"));
1263  $this->membersObject();
1264  }
1265 
1269  public function saveStatusParticipantObject(array $a_selected = null)
1270  {
1271  $ilCtrl = $this->ctrl;
1272 
1273  $member_id = (int) $_GET["part_id"];
1274  $data = array();
1275  foreach (array_keys($_POST["id"]) as $ass_id) {
1276  if (is_array($a_selected) &&
1277  !in_array($ass_id, $a_selected)) {
1278  continue;
1279  }
1280 
1281  $data[$ass_id][$member_id] = array(
1282  "status" => ilUtil::stripSlashes($_POST["status"][$ass_id])
1283  );
1284 
1285  if (array_key_exists("mark", $_POST)) {
1286  $data[$ass_id][$member_id]["mark"] = ilUtil::stripSlashes($_POST["mark"][$ass_id]);
1287  }
1288  if (array_key_exists("notice", $_POST)) {
1289  $data[$ass_id][$member_id]["notice"] = ilUtil::stripSlashes($_POST["notice"][$ass_id]);
1290  }
1291  }
1292 
1293  $ilCtrl->setParameter($this, "part_id", $member_id); // #17629
1294  $this->saveStatus($data);
1295  }
1296 
1297 
1298  public function saveStatusAllObject(array $a_selected = null, $a_redirect = true)
1299  {
1300  $user_ids = (array) array_keys((array) $_POST['id']);
1301  $filtered_user_ids = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
1302  'edit_submissions_grades',
1303  'edit_submissions_grades',
1304  $this->exercise->getRefId(),
1305  $user_ids
1306  );
1307 
1308  $data = array();
1309  foreach ($filtered_user_ids as $user_id) {
1310  if (is_array($a_selected) &&
1311  !in_array($user_id, $a_selected)) {
1312  continue;
1313  }
1314 
1315  $data[-1][$user_id] = array(
1316  "status" => ilUtil::stripSlashes($_POST["status"][$user_id])
1317  );
1318 
1319  if (array_key_exists("mark", $_POST)) {
1320  $data[-1][$user_id]["mark"] = ilUtil::stripSlashes($_POST["mark"][$user_id]);
1321  }
1322  if (array_key_exists("notice", $_POST)) {
1323  $data[-1][$user_id]["notice"] = ilUtil::stripSlashes($_POST["notice"][$user_id]);
1324  }
1325  }
1326  $this->saveStatus($data, $a_redirect);
1327  }
1328 
1329  public function saveStatusSelectedObject()
1330  {
1331  $members = $this->getMultiActionUserIds();
1332 
1333  if ($this->assignment) {
1334  $this->saveStatusAllObject(array_keys($members));
1335  } else {
1336  $this->saveStatusParticipantObject(array_keys($members));
1337  }
1338  }
1339 
1343  protected function saveStatus(array $a_data, $a_redirect = true)
1344  {
1345  $ilCtrl = $this->ctrl;
1346 
1347  $saved_for = array();
1348  foreach ($a_data as $ass_id => $users) {
1349  $ass = ($ass_id < 0)
1350  ? $this->assignment
1351  : new ilExAssignment($ass_id);
1352  foreach ($users as $user_id => $values) {
1353  // this will add team members if available
1354  $submission = new ilExSubmission($ass, $user_id);
1355  foreach ($submission->getUserIds() as $sub_user_id) {
1356  $uname = ilObjUser::_lookupName($sub_user_id);
1357  $saved_for[$sub_user_id] = $uname["lastname"] . ", " . $uname["firstname"];
1358 
1359  $member_status = $ass->getMemberStatus($sub_user_id);
1360 
1361  // see bug #22566
1362  $status = $values["status"];
1363  if ($status == "") {
1364  $status = self::GRADE_NOT_GRADED;
1365  }
1366  $member_status->setStatus($status);
1367  if (array_key_exists("mark", $values)) {
1368  $member_status->setMark($values["mark"]);
1369  }
1370  if (array_key_exists("notice", $values)) {
1371  $member_status->setNotice($values["notice"]);
1372  }
1373  $member_status->update();
1374  }
1375  }
1376  }
1377 
1378  if (count($saved_for) > 0) {
1379  $save_for_str = "(" . implode(" - ", $saved_for) . ")";
1380  }
1381 
1382  if ($a_redirect) {
1383  ilUtil::sendSuccess($this->lng->txt("exc_status_saved") . " " . $save_for_str, true);
1384  $ilCtrl->redirect($this, $this->getViewBack());
1385  }
1386  }
1387 
1392  {
1393  $res = array("result" => false);
1394 
1395  if ($this->ctrl->isAsynch()) {
1396  $ass_id = (int) $_POST["ass_id"];
1397  $user_id = (int) $_POST["mem_id"];
1398  $comment = trim($_POST["comm"]);
1399 
1400  if ($ass_id && $user_id) {
1401  $submission = new ilExSubmission($this->assignment, $user_id);
1402  $user_ids = $submission->getUserIds();
1403 
1404  $all_members = new ilExerciseMembers($this->exercise);
1405  $all_members = $all_members->getMembers();
1406 
1407  $reci_ids = array();
1408  foreach ($user_ids as $user_id) {
1409  if (in_array($user_id, $all_members)) {
1410  $member_status = $this->assignment->getMemberStatus($user_id);
1411  $member_status->setComment(ilUtil::stripSlashes($comment));
1412  $member_status->setFeedback(true);
1413  $member_status->update();
1414 
1415  if (trim($comment)) {
1416  $reci_ids[] = $user_id;
1417  }
1418  }
1419  }
1420 
1421  if (sizeof($reci_ids)) {
1422  // send notification
1423  $this->exercise->sendFeedbackFileNotification(
1424  null,
1425  $reci_ids,
1426  $ass_id,
1427  true
1428  );
1429  }
1430 
1431  $res = array("result" => true, "snippet" => nl2br($comment));
1432  }
1433  }
1434 
1435  echo(json_encode($res));
1436  exit();
1437  }
1438 
1442  public function exportExcelObject()
1443  {
1444  $this->exercise->exportGradesExcel();
1445  exit;
1446  }
1447 
1448 
1449  //
1450  // TEAM
1451  //
1452 
1453  public function createTeamsObject()
1454  {
1455  $ilCtrl = $this->ctrl;
1456 
1457  $members = $this->getMultiActionUserIds(true);
1458 
1459  $new_members = array();
1460 
1461  foreach ($members as $group) {
1462  if (is_array($group)) {
1463  $new_members = array_merge($new_members, $group);
1464 
1465  $first_user = $group;
1466  $first_user = array_shift($first_user);
1467  $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1468  foreach ($group as $user_id) {
1469  $team->removeTeamMember($user_id);
1470  }
1471  } else {
1472  $new_members[] = $group;
1473  }
1474  }
1475 
1476  if (sizeof($new_members)) {
1477  // see ilExSubmissionTeamGUI::addTeamMemberActionObject()
1478 
1479  $first_user = array_shift($new_members);
1480  $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user, true);
1481  if (sizeof($new_members)) {
1482  foreach ($new_members as $user_id) {
1483  $team->addTeamMember($user_id);
1484  }
1485  }
1486 
1487  // re-evaluate complete team, as some members might have had submitted
1488  $submission = new ilExSubmission($this->assignment, $first_user);
1489  $this->exercise->processExerciseStatus(
1490  $this->assignment,
1491  $team->getMembers(),
1492  $submission->hasSubmitted(),
1493  $submission->validatePeerReviews()
1494  );
1495  }
1496 
1497  ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
1498  $ilCtrl->redirect($this, "members");
1499  }
1500 
1501  public function dissolveTeamsObject()
1502  {
1503  $ilCtrl = $this->ctrl;
1504 
1505  $members = $this->getMultiActionUserIds(true);
1506 
1507  foreach ($members as $group) {
1508  // if single member - nothing to do
1509  if (is_array($group)) {
1510  // see ilExSubmissionTeamGUI::removeTeamMemberObject()
1511 
1512  $first_user = $group;
1513  $first_user = array_shift($first_user);
1514  $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first_user);
1515  foreach ($group as $user_id) {
1516  $team->removeTeamMember($user_id);
1517  }
1518 
1519  // reset ex team members, as any submission is not valid without team
1520  $this->exercise->processExerciseStatus(
1521  $this->assignment,
1522  $group,
1523  false
1524  );
1525  }
1526  }
1527 
1528  ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
1529  $ilCtrl->redirect($this, "members");
1530  }
1531 
1532  public function adoptTeamsFromGroupObject(ilPropertyFormGUI $a_form = null)
1533  {
1534  $ilCtrl = $this->ctrl;
1535  $ilTabs = $this->tabs_gui;
1536  $lng = $this->lng;
1537  $tpl = $this->tpl;
1538 
1539  $ilTabs->clearTargets();
1540  $ilTabs->setBackTarget(
1541  $lng->txt("back"),
1542  $ilCtrl->getLinkTarget($this, $this->getViewBack())
1543  );
1544 
1545  if (!$a_form) {
1546  $a_form = $this->initGroupForm();
1547  }
1548  $tpl->setContent($a_form->getHTML());
1549  }
1550 
1551  protected function initGroupForm()
1552  {
1553  $lng = $this->lng;
1554 
1555  $form = new ilPropertyFormGUI();
1556  $form->setTitle($lng->txt("exc_adopt_group_teams") . " - " . $this->assignment->getTitle());
1557  $form->setFormAction($this->ctrl->getFormAction($this, "createTeamsFromGroups"));
1558 
1559  $all_members = array();
1560  foreach (ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId()) as $grp_id => $group) {
1561  if (sizeof($group["members"])) {
1562  $grp_team = new ilCheckboxGroupInputGUI($lng->txt("obj_grp") . " \"" . $group["title"] . "\"", "grpt_" . $grp_id);
1563  $grp_value = $options = array();
1564  foreach ($group["members"] as $user_id) {
1565  $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1566  $options[$user_id] = $user_name;
1567  if (!in_array($user_id, $all_members)) {
1568  $grp_value[] = $user_id;
1569  $all_members[] = $user_id;
1570  }
1571  }
1572  asort($options);
1573  foreach ($options as $user_id => $user_name) {
1574  $grp_team->addOption(new ilCheckboxOption($user_name, $user_id));
1575  }
1576  $grp_team->setValue($grp_value);
1577  $form->addItem($grp_team);
1578  } else {
1579  $grp_team = new ilNonEditableValueGUI($group["title"]);
1580  $grp_team->setValue($lng->txt("exc_adopt_group_teams_no_members"));
1581  $form->addItem($grp_team);
1582  }
1583  }
1584 
1585  if (sizeof($all_members)) {
1586  $form->addCommandButton("createTeamsFromGroups", $lng->txt("save"));
1587  }
1588  $form->addCommandButton("members", $lng->txt("cancel"));
1589 
1590  return $form;
1591  }
1592 
1594  {
1595  $lng = $this->lng;
1596 
1597  $form = $this->initGroupForm();
1598  if ($form->checkInput()) {
1599  $map = ilExAssignmentTeam::getGroupMembersMap($this->exercise->getRefId());
1600  $all_members = $teams = array();
1601  $valid = true;
1602  foreach (array_keys($map) as $grp_id) {
1603  $postvar = "grpt_" . $grp_id;
1604  $members = $_POST[$postvar];
1605  if (is_array($members)) {
1606  $teams[] = $members;
1607  $invalid_team_members = array();
1608 
1609  foreach ($members as $user_id) {
1610  if (!array_key_exists($user_id, $all_members)) {
1611  $all_members[$user_id] = $grp_id;
1612  } else {
1613  // user is selected in multiple groups
1614  $invalid_team_members[] = $user_id;
1615  }
1616  }
1617 
1618  if (sizeof($invalid_team_members)) {
1619  $valid = false;
1620 
1621  $alert = array();
1622  foreach ($invalid_team_members as $user_id) {
1623  $user_name = ilUserUtil::getNamePresentation($user_id, false, false, "", true);
1624  $grp_title = $map[$all_members[$user_id]]["title"];
1625  $alert[] = sprintf($lng->txt("exc_adopt_group_teams_conflict"), $user_name, $grp_title);
1626  }
1627  $input = $form->getItemByPostVar($postvar);
1628  $input->setAlert(implode("<br/>", $alert));
1629  }
1630  }
1631  }
1632  if ($valid) {
1633  if (sizeof($teams)) {
1634  $existing_users = array_keys(ilExAssignmentTeam::getAssignmentTeamMap($this->assignment->getId()));
1635 
1636  // create teams from group selections
1637  $sum = array("added" => 0, "blocked" => 0);
1638  foreach ($teams as $members) {
1639  foreach ($members as $user_id) {
1640  if (!$this->exercise->members_obj->isAssigned($user_id)) {
1641  $this->exercise->members_obj->assignMember($user_id);
1642  }
1643 
1644  if (!in_array($user_id, $existing_users)) {
1645  $sum["added"]++;
1646  } else {
1647  $sum["blocked"]++;
1648  }
1649  }
1650 
1651  $first = array_shift($members);
1652  $team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $first, true);
1653 
1654  // getTeamId() does NOT send notification
1655  // $team->sendNotification($this->exercise->getRefId(), $first, "add");
1656 
1657  if (sizeof($members)) {
1658  foreach ($members as $user_id) {
1659  $team->addTeamMember($user_id);
1660  }
1661  }
1662  }
1663 
1664  $mess = array();
1665  if ($sum["added"]) {
1666  $mess[] = sprintf($lng->txt("exc_adopt_group_teams_added"), $sum["added"]);
1667  }
1668  if ($sum["blocked"]) {
1669  $mess[] = sprintf($lng->txt("exc_adopt_group_teams_blocked"), $sum["blocked"]);
1670  }
1671  if ($sum["added"]) {
1672  ilUtil::sendSuccess(implode(" ", $mess), true);
1673  } else {
1674  ilUtil::sendFailure(implode(" ", $mess), true);
1675  }
1676  }
1677  $this->ctrl->redirect($this, "members");
1678  } else {
1679  ilUtil::sendFailure($lng->txt("form_input_not_valid"));
1680  }
1681  }
1682 
1683  $form->setValuesByPost();
1684  $this->adoptTeamsFromGroupObject($form);
1685  }
1686 
1687 
1691 
1692  public function initMultiFeedbackForm($a_ass_id)
1693  {
1694  $lng = $this->lng;
1695 
1696  $form = new ilPropertyFormGUI();
1697  $form->addCommandButton("uploadMultiFeedback", $lng->txt("upload"));
1698  $form->addCommandButton("members", $lng->txt("cancel"));
1699 
1700  // multi feedback file
1701  $fi = new ilFileInputGUI($lng->txt("exc_multi_feedback_file"), "mfzip");
1702  $fi->setSuffixes(array("zip"));
1703  $fi->setRequired(true);
1704  $form->addItem($fi);
1705 
1706  $form->setTitle(ilExAssignment::lookupTitle($a_ass_id));
1707  $form->setFormAction($this->ctrl->getFormAction($this, "uploadMultiFeedback"));
1708 
1709  return $form;
1710  }
1711 
1718  public function showMultiFeedbackObject(ilPropertyFormGUI $a_form = null)
1719  {
1720  $ilToolbar = $this->toolbar;
1721  $lng = $this->lng;
1722  $tpl = $this->tpl;
1723 
1724  ilUtil::sendInfo($lng->txt("exc_multi_feedb_info"));
1725 
1726  $this->addSubTabs("assignment");
1727 
1728  // #13719
1729  $button = ilLinkButton::getInstance();
1730  $button->setCaption("exc_download_zip_structure");
1731  $button->setUrl($this->ctrl->getLinkTarget($this, "downloadMultiFeedbackZip"));
1732  $button->setOmitPreventDoubleSubmission(true);
1733  $ilToolbar->addButtonInstance($button);
1734 
1735  if (!$a_form) {
1736  $a_form = $this->initMultiFeedbackForm($this->assignment->getId());
1737  }
1738 
1739  $tpl->setContent($a_form->getHTML());
1740  }
1741 
1746  {
1747  $this->assignment->sendMultiFeedbackStructureFile($this->exercise);
1748  }
1749 
1753  public function uploadMultiFeedbackObject()
1754  {
1755  // #11983
1756  $form = $this->initMultiFeedbackForm($this->assignment->getId());
1757  if ($form->checkInput()) {
1758  try {
1759  $this->assignment->uploadMultiFeedbackFile(ilUtil::stripSlashesArray($_FILES["mfzip"]));
1760  $this->ctrl->redirect($this, "showMultiFeedbackConfirmationTable");
1761  } catch (ilExerciseException $e) {
1762  ilUtil::sendFailure($e->getMessage(), true);
1763  $this->ctrl->redirect($this, "showMultiFeedback");
1764  }
1765  }
1766 
1767  $form->setValuesByPost();
1768  $this->showMultiFeedbackObject($form);
1769  }
1770 
1778  {
1779  $tpl = $this->tpl;
1780 
1781  $this->addSubTabs("assignment");
1782 
1783  $tab = new ilFeedbackConfirmationTable2GUI($this, "showMultiFeedbackConfirmationTable", $this->assignment);
1784  $tpl->setContent($tab->getHTML());
1785  }
1786 
1790  public function cancelMultiFeedbackObject()
1791  {
1792  $this->assignment->clearMultiFeedbackDirectory();
1793  $this->ctrl->redirect($this, "members");
1794  }
1795 
1799  public function saveMultiFeedbackObject()
1800  {
1801  $this->assignment->saveMultiFeedbackFiles($_POST["file"], $this->exercise);
1802 
1803  ilUtil::sendSuccess($this->lng->txt("msg_obj_modified"), true);
1804  $this->ctrl->redirect($this, "members");
1805  }
1806 
1807 
1808  //
1809  // individual deadlines
1810  //
1811 
1812  protected function initIndividualDeadlineModal()
1813  {
1814  $lng = $this->lng;
1815  $tpl = $this->tpl;
1816 
1817  // prepare modal+
1818  $modal = ilModalGUI::getInstance();
1819  $modal->setHeading($lng->txt("exc_individual_deadline"));
1820  $modal->setId("ilExcIDl");
1821  $modal->setBody('<div id="ilExcIDlBody"></div>');
1822  $modal = $modal->getHTML();
1823 
1824  $ajax_url = $this->ctrl->getLinkTarget($this, "handleIndividualDeadlineCalls", "", true, false);
1825 
1826  $tpl->addJavaScript("./Modules/Exercise/js/ilExcIDl.js", true, 3);
1827  $tpl->addOnloadCode('il.ExcIDl.init("' . $ajax_url . '");');
1828 
1830 
1831  return $modal;
1832  }
1833 
1834  protected function parseIndividualDeadlineData(array $a_data)
1835  {
1836  if ($a_data) {
1837  $map = array();
1838  $ass_tmp = array();
1839  foreach ($a_data as $item) {
1840  $item = explode("_", $item);
1841  $ass_id = $item[0];
1842  $user_id = $item[1];
1843 
1844  if (!array_key_exists($ass_id, $ass_tmp)) {
1845  if ($this->assignment &&
1846  $ass_id == $this->assignment->getId()) {
1847  $ass_tmp[$ass_id] = $this->assignment;
1848  } else {
1849  $ass_tmp[$ass_id] = new ilExAssignment($ass_id);
1850  }
1851  }
1852 
1853  $map[$ass_id][] = $user_id;
1854  }
1855 
1856  return array($map, $ass_tmp);
1857  }
1858  }
1859 
1861  {
1862  $tpl = $this->tpl;
1863 
1864  $this->ctrl->saveParameter($this, "part_id");
1865 
1866  // we are done
1867  if ((bool) $_GET["dn"]) {
1868  ilUtil::sendSuccess($this->lng->txt("settings_saved"), true);
1869  $this->ctrl->redirect($this, $this->assignment
1870  ? "members"
1871  : "showParticipant");
1872  }
1873 
1874  // initial form call
1875  if ($_GET["idlid"]) {
1876  $tmp = $this->parseIndividualDeadlineData(explode(",", $_GET["idlid"]));
1877  if (is_array($tmp)) {
1878  $form = $this->initIndividualDeadlineForm($tmp[1], $tmp[0]);
1879  echo $form->getHTML() .
1880  $tpl->getOnLoadCodeForAsynch();
1881  }
1882  }
1883  // form "submit"
1884  else {
1885  $tmp = array();
1886  foreach (array_keys($_POST) as $id) {
1887  if (substr($id, 0, 3) == "dl_") {
1888  $tmp[] = substr($id, 3);
1889  }
1890  }
1891  $tmp = $this->parseIndividualDeadlineData($tmp);
1892  $ass_map = $tmp[1];
1893  $users = $tmp[0];
1894  unset($tmp);
1895 
1896  $form = $this->initIndividualDeadlineForm($ass_map, $users);
1897  $res = array();
1898  if ($valid = $form->checkInput()) {
1899  foreach ($users as $ass_id => $users) {
1900  $ass = $ass_map[$ass_id];
1901 
1902  // :TODO: should individual deadlines BEFORE extended be possible?
1903  $dl = new ilDateTime($ass->getDeadline(), IL_CAL_UNIX);
1904 
1905  foreach ($users as $user_id) {
1906  $date_field = $form->getItemByPostVar("dl_" . $ass_id . "_" . $user_id);
1907  if (ilDate::_before($date_field->getDate(), $dl)) {
1908  $date_field->setAlert(sprintf($this->lng->txt("exc_individual_deadline_before_global"), ilDatePresentation::formatDate($dl)));
1909  $valid = false;
1910  } else {
1911  $res[$ass_id][$user_id] = $date_field->getDate();
1912  }
1913  }
1914  }
1915  }
1916 
1917  if (!$valid) {
1918  $form->setValuesByPost();
1919  echo $form->getHTML() .
1920  $tpl->getOnLoadCodeForAsynch();
1921  } else {
1922  foreach ($res as $ass_id => $users) {
1923  $ass = $ass_map[$ass_id];
1924 
1925  foreach ($users as $id => $date) {
1926  $ass->setIndividualDeadline($id, $date);
1927  }
1928 
1929  $ass->recalculateLateSubmissions();
1930  }
1931 
1932  echo "ok";
1933  }
1934  }
1935 
1936  exit();
1937  }
1938 
1939  protected function initIndividualDeadlineForm(array $a_ass_map, array $ids)
1940  {
1941  $form = new ilPropertyFormGUI();
1942  $form->setFormAction($this->ctrl->getFormAction($this));
1943  $form->setName("ilExcIDlForm");
1944 
1945  foreach ($ids as $ass_id => $users) {
1946  $ass = $a_ass_map[$ass_id];
1947 
1949  $section->setTitle($ass->getTitle());
1950  $form->addItem($section);
1951 
1952  $teams = ilExAssignmentTeam::getInstancesFromMap($ass->getId());
1953 
1954  $values = $ass->getIndividualDeadlines();
1955 
1956  foreach ($users as $id) {
1957  // single user
1958  if (is_numeric($id)) {
1960  $name = $name["lastname"] . ", " . $name["firstname"];
1961  }
1962  // team
1963  else {
1964  $name = "";
1965  $team_id = (int) substr($id, 1);
1966  if (array_key_exists($team_id, $teams)) {
1967  $name = array();
1968  foreach ($teams[$team_id]->getMembers() as $member_id) {
1969  $uname = ilObjUser::_lookupName($member_id);
1970  $name[] = $uname["lastname"] . ", " . $uname["firstname"];
1971  }
1972  asort($name);
1973  $name = implode("<br />", $name);
1974  }
1975  }
1976 
1977  $dl = new ilDateTimeInputGUI($name, "dl_" . $ass_id . "_" . $id);
1978  $dl->setShowTime(true);
1979  $dl->setRequired(true);
1980  $form->addItem($dl);
1981 
1982  if (array_key_exists($id, $values)) {
1983  $dl->setDate(new ilDateTime($values[$id], IL_CAL_UNIX));
1984  }
1985  }
1986  }
1987 
1988  $form->addCommandButton("", $this->lng->txt("save"));
1989 
1990  return $form;
1991  }
1992 
1993  protected function setIndividualDeadlineObject()
1994  {
1995  // this will only get called if no selection
1996  ilUtil::sendFailure($this->lng->txt("select_one"));
1997 
1998  if ($this->assignment) {
1999  $this->membersObject();
2000  } else {
2001  $this->showParticipantObject();
2002  }
2003  }
2004 
2005  public function initFilter()
2006  {
2007  if ($_POST["filter_status"]) {
2008  $this->filter["status"] = trim(ilUtil::stripSlashes($_POST["filter_status"]));
2009  }
2010 
2011  if ($_POST["filter_feedback"]) {
2012  $this->filter["feedback"] = trim(ilUtil::stripSlashes($_POST["filter_feedback"]));
2013  }
2014 
2015  $this->lng->loadLanguageModule("search");
2016 
2017  $this->toolbar->setFormAction($this->ctrl->getFormAction($this, "listTextAssignment"));
2018 
2019  // Status
2020 
2021  if ($_POST["filter_status"]) {
2022  $this->filter["status"] = trim(ilUtil::stripSlashes($_POST["filter_status"]));
2023  }
2024 
2025  $si_status = new ilSelectInputGUI($this->lng->txt("exc_tbl_status"), "filter_status");
2026  $options = array(
2027  "" => $this->lng->txt("search_any"),
2028  self::GRADE_NOT_GRADED => $this->lng->txt("exc_notgraded"),
2029  self::GRADE_PASSED => $this->lng->txt("exc_passed"),
2030  self::GRADE_FAILED => $this->lng->txt("exc_failed")
2031  );
2032  $si_status->setOptions($options);
2033  $si_status->setValue($this->filter["status"]);
2034 
2035  $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2036  $options = array(
2037  self::FEEDBACK_FULL_SUBMISSION => $this->lng->txt("submissions_feedback"),
2038  self::FEEDBACK_ONLY_SUBMISSION => $this->lng->txt("submissions_only")
2039  );
2040  $si_feedback->setOptions($options);
2041  $si_feedback->setValue($this->filter["feedback"]);
2042 
2043  $this->toolbar->addInputItem($si_status, true);
2044 
2045  // Submissions and Feedback
2046  #24713
2047  if ($this->assignment->getPeerReview()) {
2048  if ($_POST["filter_feedback"]) {
2049  $this->filter["feedback"] = trim(ilUtil::stripSlashes($_POST["filter_feedback"]));
2050  } else {
2051  $this->filter["feedback"] = "submission_feedback";
2052  }
2053 
2054  $si_feedback = new ilSelectInputGUI($this->lng->txt("feedback"), "filter_feedback");
2055  $options = array(
2056  "submission_feedback" => $this->lng->txt("submissions_feedback"),
2057  "submission_only" => $this->lng->txt("submissions_only")
2058  );
2059  $si_feedback->setOptions($options);
2060  $si_feedback->setValue($this->filter["feedback"]);
2061 
2062  $this->toolbar->addInputItem($si_feedback, true);
2063  }
2064 
2065  //todo: old school here.
2066  $submit = ilSubmitButton::getInstance();
2067  $submit->setCaption("filter");
2068  $submit->setCommand("listTextAssignment");
2069  $this->toolbar->addButtonInstance($submit);
2070  }
2071 
2075  public function openSubmissionViewObject()
2076  {
2077  global $DIC;
2078 
2079  $ass_id = (int) $_GET["ass_id"];
2080  $member_id = (int) $_GET["member_id"];
2081 
2082  $submission = new ilExSubmission($this->assignment, $member_id);
2083 
2084  $last_opening = $submission->getLastOpeningHTMLView();
2085 
2086  $submission_time = $submission->getLastSubmission();
2087 
2088  $zip_original_full_path = $this->getSubmissionZipFilePath($submission);
2089 
2090  $zip_internal_path = $this->getWebFilePathFromExternalFilePath($zip_original_full_path);
2091 
2092  list($obj_date, $obj_id) = explode("_", basename($zip_original_full_path));
2093 
2094  $obj_dir = $this->assignment->getAssignmentType()->getStringIdentifier() . "_" . $obj_id;
2095 
2096  $index_html_file = ILIAS_WEB_DIR .
2097  DIRECTORY_SEPARATOR .
2098  CLIENT_ID .
2099  DIRECTORY_SEPARATOR .
2100  dirname($zip_internal_path) .
2101  DIRECTORY_SEPARATOR .
2102  $obj_dir .
2103  DIRECTORY_SEPARATOR .
2104  "index.html";
2105 
2106  ilWACSignedPath::signFolderOfStartFile($index_html_file);
2107 
2108  $web_filesystem = $DIC->filesystem()->web();
2109 
2110  if ($last_opening > $submission_time && $web_filesystem->has($index_html_file)) {
2111  ilUtil::redirect($index_html_file);
2112  }
2113  if ($zip_original_full_path) {
2114  $file_copied = $this->copyFileToWebDir($zip_original_full_path, $zip_internal_path);
2115 
2116  if ($file_copied) {
2117  ilUtil::unzip($file_copied, true);
2118 
2119  $web_filesystem->delete($zip_internal_path);
2120 
2121  $submission_repository = new ilExcSubmissionRepository();
2122  $submission_repository->updateWebDirAccessTime($this->assignment->getId(), $member_id);
2123 
2124  ilUtil::redirect($index_html_file);
2125  }
2126 
2127  $error_msg = $this->lng->txt("exc_copy_zip_error");
2128  }
2129 
2130  if (!$error_msg) {
2131  $error_msg = $this->lng->txt("exc_find_zip_error");
2132  }
2133 
2134  ilUtil::sendFailure($error_msg);
2135  }
2136 
2142  protected function getSubmissionZipFilePath(ilExSubmission $submission) : ?string
2143  {
2144  $submitted = $submission->getFiles();
2145 
2146  if (count($submitted) > 0) {
2147  $submitted = array_pop($submitted);
2148 
2149  return $submitted['filename'];
2150  }
2151 
2152  return null;
2153  }
2154 
2161  protected function copyFileToWebDir(string $origin_path_filename, string $internal_file_path) : ?string
2162  {
2163  global $DIC;
2164 
2165  $web_filesystem = $DIC->filesystem()->web();
2166  $data_filesystem = $DIC->filesystem()->storage();
2167 
2168  $internal_dirs = dirname($internal_file_path);
2169  $zip_file = basename($internal_file_path);
2170 
2171  if ($data_filesystem->has($internal_file_path)) {
2172  if (!$web_filesystem->hasDir($internal_dirs)) {
2173  $web_filesystem->createDir($internal_dirs);
2174  }
2175 
2176  if (!$web_filesystem->has($internal_file_path)) {
2177  $stream = $data_filesystem->readStream($internal_file_path);
2178  $web_filesystem->writeStream($internal_file_path, $stream);
2179 
2180  return ILIAS_ABSOLUTE_PATH .
2181  DIRECTORY_SEPARATOR .
2182  ILIAS_WEB_DIR .
2183  DIRECTORY_SEPARATOR .
2184  CLIENT_ID .
2185  DIRECTORY_SEPARATOR .
2186  $internal_dirs .
2187  DIRECTORY_SEPARATOR .
2188  $zip_file;
2189  }
2190  }
2191 
2192  return null;
2193  }
2194 
2200  protected function getWebFilePathFromExternalFilePath(string $external_file_path) : string
2201  {
2202  list($external_path, $internal_file_path) = explode(CLIENT_ID . "/", $external_file_path);
2203 
2204  return $internal_file_path;
2205  }
2206 
2207  /*
2208  * Add the Back link to the tabs. (used in submission list and submission compare)
2209  */
2210  protected function setBackToMembers()
2211  {
2212  //tabs
2213  $this->tabs_gui->clearTargets();
2214  $this->tabs_gui->setBackTarget(
2215  $this->lng->txt("back"),
2216  $this->ctrl->getLinkTarget($this, "members")
2217  );
2218  }
2219 
2224  public function collectFeedbackDataFromPeer(array $a_data) : array
2225  {
2226  $user = new ilObjUser($a_data["user_id"]);
2227  $uname = $user->getFirstname() . " " . $user->getLastname();
2228 
2229  $data = array(
2230  "uid" => $a_data["user_id"],
2231  "uname" => $uname,
2232  "udate" => $a_data["ts"],
2233  "utext" => ilRTE::_replaceMediaObjectImageSrc($a_data["atext"], 1) // mob id to mob src
2234  );
2235 
2236  //get data peer and assign it
2237  $peer_review = new ilExPeerReview($this->assignment);
2238  $data["peer"] = array();
2239  foreach ($peer_review->getPeerReviewsByPeerId($a_data['user_id']) as $key => $value) {
2240  $data["peer"][] = $value['giver_id'];
2241  }
2242 
2243  $data["fb_received"] = count($data["peer"]);
2244  $data["fb_given"] = $peer_review->countGivenFeedback(true, $a_data["user_id"]);
2245 
2246  return $data;
2247  }
2248 }
addMembersObject($a_user_ids=array())
Add new partipant.
static _lookupLogin($a_user_id)
lookup login
static sortArray( $array, $a_array_sortby, $a_array_sortorder=0, $a_numeric=false, $a_keep_keys=false)
sortArray
static _lookupName($a_user_id)
lookup user name
deassignMembersObject()
Deassign members from exercise.
exit
Definition: login.php:29
showGradesOverviewObject()
Show grades overview.
static getAssignmentDataOfExercise($a_exc_id)
Get assignments data of an exercise in an array.
Exercise assignment.
$data
Definition: storeScorm.php:23
const IL_CAL_DATETIME
This class represents an option in a checkbox group.
Class ilExerciseMembers.
static getAdoptableGroups($a_exc_ref_id)
static getGroupMembersMap($a_exc_ref_id)
This class represents a property form user interface.
static getAssignmentTeamMap($a_ass_id)
Get team structure for assignment.
static _exists($a_id, $a_reference=false, $a_type=null)
checks if an object exists in object_data
$_GET["client_id"]
static getInstancesFromMap($a_assignment_id)
saveStatusParticipantObject(array $a_selected=null)
Save assignment status (participant view)
This class represents a section header in a property form.
This class represents a file property in a property form.
$valid
static _before(ilDateTime $start, ilDateTime $end, $a_compare_field='', $a_tz='')
compare two dates and check start is before end This method does not consider tz offsets.
Exercise participant table.
saveStatusAllObject(array $a_selected=null, $a_redirect=true)
resetOffset($a_in_determination=false)
Reset offset.
static downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members, $to_path)
Download all submitted files of an assignment (all user)
getWebFilePathFromExternalFilePath(string $external_file_path)
Get the object specific file path from an external full file path.
static _lookupId($a_user_str)
Lookup id by login.
openSubmissionViewObject()
Open HTML view for portfolio submissions.
showMultiFeedbackObject(ilPropertyFormGUI $a_form=null)
Show multi-feedback screen.
addUserFromAutoCompleteObject()
Add user as member.
Class ilExerciseMembersFilter.
const IL_CAL_UNIX
filterParticipantsByAccess()
Filter manageable members by position or rbac access.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false, $include_seconds=false)
Format a date public.
static getAssignmentParticipants(int $a_exercise_id, int $a_ass_id)
user()
Definition: user.php:4
This class represents a date/time property in a property form.
selectParticipantObject()
Select participant.
setInfo($a_info)
Set Information Text.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
$section
Definition: Utf8Test.php:83
static signFolderOfStartFile($start_file_path)
setTableId($a_val)
Set table id.
if($format !==null) $name
Definition: metadata.php:230
This class represents a hidden form property in a property form.
Exercise peer review.
redirectFeedbackMailObject()
set feedback status for member and redirect to mail screen
compareTextAssignmentsObject()
TODO -> Deal with the redirection after update the grade via action button.
saveStatus(array $a_data, $a_redirect=true)
Save status of selecte members.
addSubTabs($a_activate)
adds tabs to tab gui object
foreach($_POST as $key=> $value) $res
Download submissions and feedback for exercises.
static getInstanceByUserId($a_assignment_id, $a_user_id, $a_create_on_demand=false)
Class ilExPeerReviewGUI.
uploadMultiFeedbackObject()
Upload multi feedback file.
static getInstancesByExercise($a_exc_id)
const CLIENT_ID
Definition: constants.php:39
global $DIC
Definition: goto.php:24
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
copyFileToWebDir(string $origin_path_filename, string $internal_file_path)
Generate the directories and copy the file if necessary.
downloadMultiFeedbackZipObject()
Download multi-feedback structrue file.
static unzip(string $path_to_zip_file, bool $overwrite_existing=false, bool $unpack_flat=false)
This class represents a property in a property form.
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
static getNamePresentation( $a_user_id, $a_user_image=false, $a_profile_link=false, $a_profile_back_link="", $a_force_first_lastname=false, $a_omit_login=false, $a_sortable=true, $a_return_data_array=false, $a_ctrl_path="ilpublicuserprofilegui")
Default behaviour is:
setOptions($a_options)
Set Options.
static getAssignmentFilesByUsers(int $a_exc_id, int $a_ass_id, array $a_users)
static getInstanceByObjId($a_obj_id, $stop_on_error=true)
get an instance of an Ilias object by object id
$comment
Definition: buildRTE.php:83
static _lookupType($a_id, $a_reference=false)
lookup object type
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
const SIGNATURE_KEY
Session parameter for the hash.
static stripSlashesArray($a_arr, $a_strip_html=true, $a_allow="")
Strip slashes from array.
Class ilExerciseManagementGUI.
confirmDeassignMembersObject()
Confirm deassigning members.
static getInstance()
Get instance.
cancelMultiFeedbackObject()
Cancel Multi Feedback.
sendMembersObject()
Send assignment per mail to participants.
This class represents a non editable value in a property form.
membersObject()
All participants and submission of one assignment.
saveEvaluationFromModalObject()
Save assignment submission grade(status) and comment from the roundtrip modal.
saveCommentForLearnersObject()
Save comment for learner (asynch)
getSubmissionZipFilePath(ilExSubmission $submission)
Returns the ZIP file path from outside web directory.
This class represents a text area property in a property form.
static getRedirectTarget( $gui, string $cmd, array $gui_params=[], array $mail_params=[], array $context_params=[])
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
adoptTeamsFromGroupObject(ilPropertyFormGUI $a_form=null)
showMultiFeedbackConfirmationTableObject()
Show multi feedback confirmation table.
Exercise submission //TODO: This class has to much static methods related to delivered "files"...
static getLogger($a_component_id)
Get component logger.
$url
static fillAutoCompleteToolbar($parent_object, ilToolbarGUI $toolbar=null, $a_options=array(), $a_sticky=false)
fill toolbar with
saveMultiFeedbackObject()
Save multi feedback.
File System Explorer GUI class.
filter()
Definition: filter.php:2
static redirect($a_script)
Exercise participant table.
setSuffixes($a_suffixes)
Set Accepted Suffixes.
getFiles(array $a_file_ids=null, $a_only_valid=false, $a_min_timestamp=null)
Get submission items (not only files)
__construct(ilExerciseInternalService $service, ilExAssignment $a_ass=null)
Constructor.
$_POST["username"]
Object-based submissions (ends up as static file)
initIndividualDeadlineForm(array $a_ass_map, array $ids)
static lookupTitle($a_id)
Lookup title.
downloadAllObject()
Download all submitted files (of all members).
const ILIAS_WEB_DIR
Definition: constants.php:43
Confirmation screen class.
Exercise exceptions class.