ILIAS  trunk Revision v11.0_alpha-1731-gff9cd7e2bd3
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
PropertyAndActionBuilderUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
28 use ILIAS\UI\Component\Button\Primary as ButtonPrimary;
30 
32 {
33  public const PROP_DEADLINE = "deadline";
34  public const PROP_REQUIREMENT = "requirement";
35  public const PROP_SUBMISSION = "submission";
36  public const PROP_TYPE = "type";
37  public const PROP_GRADING = "grading";
38  public const PROP_MARK = "mark";
39 
40  public const SEC_INSTRUCTIONS = "instructions";
41  public const SEC_INSTRUCTIONS_OV = "instructions_overview";
42  public const SEC_FILES = "files";
43  public const SEC_SCHEDULE = "schedule";
44  public const SEC_TEAM = "team";
45  public const SEC_SUBMISSION = "submission";
46  public const SEC_PEER_FEEDBACK = "peer_feedback";
47  public const SEC_TUTOR_EVAL = "tutor_eval";
48  public const SEC_SAMPLE_SOLUTION = "sample_solution";
51  protected \ilLanguage $lng;
53  protected \ilCtrl $ctrl;
54  protected \ilExAssignmentTypes $types;
55 
56  protected int $user_builded = 0;
57  protected int $ass_builded = 0;
58  protected \ilExcAssMemberState $state;
59  protected \ilExSubmission $submission;
60  protected \ilExAssignmentTypesGUI $types_gui;
61  protected \ilObjExercise $exc;
62  protected \ilExAssignment $ex_ass;
63  protected \ILIAS\MediaObjects\MediaType\MediaTypeManager $media_type;
65  protected \ilExAssignmentInfo $info;
66 
67  protected int $user_id;
68  protected string $lead_text = "";
69  protected array $head_properties = [];
70  protected array $properties = [];
71  protected array $actions = [];
72  protected array $views = [];
73  protected array $main_action = [];
74  protected array $additional_head_properties = [];
75  protected bool $instructions_hidden = false;
76 
77  public function __construct(
78  \ilObjExercise $exc,
79  MandatoryAssignmentsManager $mandatory_manager,
80  InternalDomainService $domain_service,
81  InternalGUIService $gui_service
82  ) {
83  global $DIC;
84 
85  $this->exc = $exc;
86  $this->media_type = $DIC->mediaObjects()->internal()->domain()->mediaType();
87  $this->domain = $domain_service;
88  $this->gui = $gui_service;
89  $this->lng = $domain_service->lng();
90  $this->mandatory_manager = $mandatory_manager;
91  $this->lng->loadLanguageModule("exc");
92  $this->ctrl = $gui_service->ctrl();
93  $this->types_gui = $gui_service->assignment()->types();
94  $this->types = \ilExAssignmentTypes::getInstance();
95  }
96 
97  public function build(
98  Assignment $ass,
99  int $user_id
100  ): void {
101  if ($this->user_builded === $user_id && $this->ass_builded === $ass->getId()) {
102  return;
103  }
104  $this->assignment = $ass;
105  $this->user_id = $user_id;
106  $this->state = \ilExcAssMemberState::getInstanceByIds($ass->getId(), $user_id);
107  $this->info = new \ilExAssignmentInfo($ass->getId(), $user_id);
108  $this->ex_ass = new \ilExAssignment($this->assignment->getId());
109  $this->submission = new \ilExSubmission($this->ex_ass, $user_id);
110  $this->lead_text = "";
111  $this->head_properties = [];
112  $this->views = [];
113  $this->additional_head_properties = [];
114  $this->main_action = [];
115  $this->actions = [];
116  $this->buildHead();
117  $this->buildBody();
118  $this->user_builded = $user_id;
119  $this->ass_builded = $ass->getId();
120  }
121 
122  public function getSections(bool $include_schedule = true, bool $overview = false): array
123  {
124  $secs = [];
125  $secs[self::SEC_INSTRUCTIONS] = $this->lng->txt("exc_instruction");
126  if ($overview) {
127  $secs[self::SEC_INSTRUCTIONS_OV] = "";
128  }
129  if ($include_schedule) {
130  $secs[self::SEC_SCHEDULE] = $this->lng->txt("exc_schedule");
131  }
132  $secs[self::SEC_FILES] = $this->lng->txt("exc_files");
133  $secs[self::SEC_TEAM] = $this->lng->txt("exc_team");
134  $secs[self::SEC_SUBMISSION] = $this->lng->txt("exc_submission");
135  $secs[self::SEC_PEER_FEEDBACK] = $this->lng->txt("exc_peer_review");
136  $secs[self::SEC_TUTOR_EVAL] = $this->lng->txt("exc_feedback_from_tutor");
137  $secs[self::SEC_SAMPLE_SOLUTION] = $this->lng->txt("exc_global_feedback_file");
138 
139  return $secs;
140  }
141 
142  public function getSectionTitle(string $sec): string
143  {
144  $secs = $this->getSections();
145  return $secs[$sec] ?? "";
146  }
147 
148  public function getLeadText(): string
149  {
150  return $this->lead_text;
151  }
152 
153  public function getHeadProperty(string $type): ?array
154  {
155  return $this->head_properties[$type] ?? null;
156  }
157 
158  public function getAdditionalHeadProperties(): array
159  {
161  }
162 
163  protected function setLeadText(string $text): void
164  {
165  $this->lead_text = $text;
166  }
167 
168  protected function setInstructionsHidden(bool $hidden): void
169  {
170  $this->instructions_hidden = $hidden;
171  }
172 
173  public function getInstructionsHidden(): bool
174  {
176  }
177 
178  protected function setHeadProperty(string $type, string $prop, string $val): void
179  {
180  $this->head_properties[$type] = [
181  "prop" => $prop,
182  "val" => $val
183  ];
184  }
185 
186  public function addAdditionalHeadProperty(string $prop, string $val): void
187  {
188  $this->additional_head_properties[] = [
189  "prop" => $prop,
190  "val" => $val
191  ];
192  }
193 
194  public function addProperty(string $section, string $prop, string $val): void
195  {
196  $this->properties[$section][] = [
197  "prop" => $prop,
198  "val" => $val
199  ];
200  }
201 
202  public function getProperties(string $section): array
203  {
204  return $this->properties[$section] ?? [];
205  }
206 
207  public function addAction(string $section, Component $button_or_link): void
208  {
209  $this->actions[$section][] = $button_or_link;
210  }
211 
212  public function getActions(string $section): array
213  {
214  return $this->actions[$section] ?? [];
215  }
216 
217  public function setMainAction(string $section, ButtonPrimary $button): void
218  {
219  $this->main_action[$section] = $button;
220  }
221 
222  public function getMainAction(string $section): ?ButtonPrimary
223  {
224  return $this->main_action[$section] ?? null;
225  }
226 
227  public function addView(string $id, string $txt, string $url): void
228  {
229  $this->views[] = [
230  "id" => $id,
231  "txt" => $txt,
232  "url" => $url
233  ];
234  }
235 
236  public function getViews(): array
237  {
238  return $this->views;
239  }
240 
241  protected function buildHead(): void
242  {
243  $state = $this->state;
244  $lng = $this->lng;
245 
246  // after official deadline...
247  if ($state->exceededOfficialDeadline()) {
248 
249  // both submission and peer review ended
250  if ($state->hasEnded()) {
251  $this->setLeadText(
252  $lng->txt("exc_ended")
253  );
254  } else {
255  $this->setLeadText(
256  $state->getPeerReviewLeadText()
257  );
258  }
259 
260  $this->setHeadProperty(
261  self::PROP_DEADLINE,
262  $lng->txt("exc_ended_on"),
263  $state->getCommonDeadlinePresentation()
264  );
265 
266  // #14077 // this currently shows the feedback deadline during grace period
267  if ($state->getPeerReviewDeadline()) {
269  $lng->txt("exc_peer_review_deadline"),
270  $state->getPeerReviewDeadlinePresentation()
271  );
272  }
273  // not started yet
274  } elseif (!$state->hasGenerallyStarted()) {
275  if ($state->getRelativeDeadline()) {
276  $prop = $lng->txt("exc_earliest_start_time");
277  } else {
278  $prop = $lng->txt("exc_starting_on");
279  }
280  $this->setLeadText(
281  $prop . " " . $state->getGeneralStartPresentation()
282  );
283  $this->setHeadProperty(
284  self::PROP_DEADLINE,
285  $prop,
286  $state->getGeneralStartPresentation()
287  );
288  } else {
289  // deadline, but not reached
290  if ($state->getCommonDeadline() > 0) {
291  $this->setLeadText(
292  $state->getRemainingTimeLeadText()
293  );
294  $this->setHeadProperty(
295  self::PROP_DEADLINE,
296  $lng->txt("exc_edit_until"),
297  $state->getCommonDeadlinePresentation()
298  );
299  // relative deadline
300  } elseif ($state->getRelativeDeadline()) { // if we only have a relative deadline (not started yet)
301  $this->setHeadProperty(
302  self::PROP_DEADLINE,
303  $lng->txt("exc_rem_time_after_start"),
304  $state->getRelativeDeadlinePresentation()
305  );
306  $this->setLeadText(
307  $state->getRelativeDeadlineStartLeadText()
308  );
309 
310  if ($state->getLastSubmissionOfRelativeDeadline()) { // if we only have a relative deadline (not started yet)
312  $lng->txt("exc_rel_last_submission"),
313  $state->getLastSubmissionOfRelativeDeadlinePresentation()
314  );
315  }
316  } elseif ($this->assignment->getDeadlineMode() === \ilExAssignment::DEADLINE_ABSOLUTE_INDIVIDUAL) {
317  if ($state->needsIndividualDeadline()) {
318  if ($state->hasRequestedIndividualDeadline()) {
319  $this->setLeadText(
320  $this->lng->txt("exc_lead_wait_for_idl")
321  );
322  } else {
323  $this->setLeadText(
324  $this->lng->txt("exc_lead_request_idl")
325  );
326  }
327  $this->setHeadProperty(
328  self::PROP_DEADLINE,
329  $lng->txt("exc_deadline"),
330  $lng->txt("exc_deadline_not_set_yet")
331  );
332  } else {
333  $this->setLeadText(
334  $state->getRemainingTimeLeadText()
335  );
336  $this->setHeadProperty(
337  self::PROP_DEADLINE,
338  $lng->txt("exc_edit_until"),
339  $state->getIndividualDeadlinePresentation()
340  );
341  }
342  } else {
343  // no deadline
344  $this->setLeadText(
345  $this->lng->txt("exc_submit_anytime")
346  );
347  $this->setHeadProperty(
348  self::PROP_DEADLINE,
349  $lng->txt("exc_edit_until"),
350  $lng->txt("exc_no_deadline")
351  );
352  }
353 
354  if ($state->getIndividualDeadline() > 0 &&
355  $this->assignment->getDeadlineMode() !== \ilExAssignment::DEADLINE_ABSOLUTE_INDIVIDUAL) {
357  $lng->txt("exc_individual_deadline"),
358  $state->getIndividualDeadlinePresentation()
359  );
360  }
361  }
362 
363  if ($this->mandatory_manager->isMandatoryForUser($this->assignment->getId(), $this->user_id)) {
364  $this->setHeadProperty(
365  self::PROP_REQUIREMENT,
366  $lng->txt("exc_requirement"),
367  $lng->txt("exc_mandatory")
368  );
369  } else {
370  $this->setHeadProperty(
371  self::PROP_REQUIREMENT,
372  $lng->txt("exc_requirement"),
373  $lng->txt("exc_optional")
374  );
375  }
376 
377  // submission property
378  if ($this->submission->hasSubmitted()) {
379  $last_sub = $this->submission->getLastSubmission();
380  if ($last_sub) {
381  $last_sub = \ilDatePresentation::formatDate(new \ilDateTime($last_sub, IL_CAL_DATETIME));
382  $this->setHeadProperty(
383  self::PROP_SUBMISSION,
384  $this->lng->txt("exc_last_submission"),
385  $last_sub
386  );
387  }
388  } else {
389  $this->setHeadProperty(
390  self::PROP_SUBMISSION,
391  $this->lng->txt("exc_last_submission"),
392  $this->lng->txt("exc_no_submission_yet")
393  );
394  }
395 
396  // type property
397  $ass_type = $this->types->getById($this->assignment->getType());
398  $this->setHeadProperty(
399  self::PROP_TYPE,
400  $this->lng->txt("exc_type"),
401  $ass_type->getTitle()
402  );
403 
404  // grading property
405  if (!$this->state->isFuture()) {
406  $status = $this->ex_ass->getMemberStatus($this->user_id)->getStatus();
407  if ($status !== "") {
408  $this->setHeadProperty(
409  self::PROP_GRADING,
410  $lng->txt("status"),
411  $lng->txt("exc_" . $status)
412  );
413  }
414  }
415 
416  // mark
417  if (!$this->state->isFuture()) {
418  $mark = $this->ex_ass->getMemberStatus($this->user_id)->getMark();
419  if ($mark !== "") {
420  $this->setHeadProperty(
421  self::PROP_MARK,
422  $lng->txt("exc_mark"),
423  $mark
424  );
425  }
426  }
427 
428  // status icon
429  /*
430  $tpl->setVariable(
431  "ICON_STATUS",
432  $this->getIconForStatus(
433  $a_ass->getMemberStatus()->getStatus(),
434  ilLPStatusIcons::ICON_VARIANT_SHORT
435  )
436  );*/
437  }
438 
439  protected function buildBody(): void
440  {
441  // main view
442  $this->ctrl->setParameterByClass(\ilAssignmentPresentationGUI::class, "ass_id", $this->assignment->getId());
443  $this->addView(
444  "ass",
445  $this->lng->txt("overview"),
446  $this->ctrl->getLinkTargetByClass(\ilAssignmentPresentationGUI::class, "")
447  );
448 
449  if ($this->state->areInstructionsVisible()) {
450  $this->buildInstructions();
451  $this->buildFiles();
452  } else {
453  $this->setInstructionsHidden(true);
454  }
455 
456  $this->buildSchedule();
457 
458  if ($this->state->hasSubmissionStarted()) {
459  $this->buildSubmission();
460  $this->buildPeerFeedback();
461  $this->buildSampleSolution();
462  }
463  }
464 
465 
466  protected function buildInstructions(): void
467  {
468  $inst = $this->info->getInstructionInfo();
469  if (count($inst) > 0) {
470  $this->addProperty(
471  self::SEC_INSTRUCTIONS,
472  "",
473  $inst["instruction"]["value"]
474  );
475  $link = $this->gui->ui()->factory()->link()->standard(
476  $this->lng->txt("exc_show_instructions"),
477  $this->ctrl->getLinkTargetByClass(\ilAssignmentPresentationGUI::class, "")
478  );
479  $this->addAction(
480  self::SEC_INSTRUCTIONS_OV,
481  $link
482  );
483  }
484  }
485 
490  protected function buildSchedule(): void
491  {
492 
493  $info = $this->info;
494  $schedule = $info->getScheduleInfo();
495  $ilCtrl = $this->ctrl;
496  $lng = $this->lng;
497 
498  $state = $this->state;
499 
500  if ($state->getGeneralStart() > 0) {
501  $this->addProperty(
502  self::SEC_SCHEDULE,
503  $schedule["start_time"]["txt"],
504  $schedule["start_time"]["value"]
505  );
506  }
507 
508  if ($state->getCommonDeadline()) { // if we have a common deadline (target timestamp)
509  $this->addProperty(
510  self::SEC_SCHEDULE,
511  $schedule["until"]["txt"],
512  $schedule["until"]["value"]
513  );
514  } elseif ($state->getRelativeDeadline()) { // if we only have a relative deadline (not started yet)
515  $but = "";
516  if ($state->hasGenerallyStarted()) {
517  $ilCtrl->setParameterByClass("ilobjexercisegui", "ass_id", $this->assignment->getId());
518  $but = $this->gui->ui()->factory()->button()->primary($lng->txt("exc_start_assignment"), $ilCtrl->getLinkTargetByClass("ilobjexercisegui", "startAssignment"));
519  $ilCtrl->setParameterByClass("ilobjexercisegui", "ass_id", null);
520  $this->setMainAction(
521  self::SEC_SCHEDULE,
522  $but
523  );
524  }
525  $this->addProperty(
526  self::SEC_SCHEDULE,
527  $schedule["time_after_start"]["txt"],
528  $schedule["time_after_start"]["value"]
529  );
530 
531  if ($state->getLastSubmissionOfRelativeDeadline()) { // if we only have a relative deadline (not started yet)
532  $this->addProperty(
533  self::SEC_SCHEDULE,
534  $lng->txt("exc_rel_last_submission"),
535  $state->getLastSubmissionOfRelativeDeadlinePresentation()
536  );
537  }
538  } elseif ($state->needsIndividualDeadline()) {
539  if ($state->hasRequestedIndividualDeadline()) {
540  $this->addProperty(
541  self::SEC_SCHEDULE,
542  $this->lng->txt("exc_deadline"),
543  $this->lng->txt("exc_idl_tutor_needed")
544  );
545  } else {
546  $this->addProperty(
547  self::SEC_SCHEDULE,
548  $this->lng->txt("exc_deadline"),
549  $this->lng->txt("exc_idl_request_and_tutor_needed")
550  );
551  $ilCtrl->setParameterByClass("ilobjexercisegui", "ass_id", $this->assignment->getId());
552  $but = $this->gui->ui()->factory()->button()->primary($lng->txt("exc_request_deadline"), $ilCtrl->getLinkTargetByClass("ilobjexercisegui", "requestDeadline"));
553  $ilCtrl->setParameterByClass("ilobjexercisegui", "ass_id", null);
554  $this->setMainAction(
555  self::SEC_SCHEDULE,
556  $but
557  );
558  }
559  }
560 
561  if ($state->getOfficialDeadline() > $state->getCommonDeadline()) {
562  $this->addProperty(
563  self::SEC_SCHEDULE,
564  $schedule["individual_deadline"]["txt"],
565  $schedule["individual_deadline"]["value"]
566  );
567  }
568 
569  if ($state->hasSubmissionStarted()) {
570  $this->addProperty(
571  self::SEC_SCHEDULE,
572  $schedule["time_to_send"]["txt"],
573  $schedule["time_to_send"]["value"]
574  );
575  }
576  }
577 
578  protected function builPublicSubmissions(): void
579  {
580  // submissions are visible, even if other users may still have a larger individual deadline
581  if ($this->state->hasSubmissionEnded()) {
582  $link = $this->gui->ui()->factory()->link()->standard(
583  $this->lng->txt("exc_public_submission"),
584  $this->getSubmissionLink("listPublicSubmissions")
585  );
586  $this->addAction(
587  self::SEC_SUBMISSION,
588  $link
589  );
590  $this->addView(
591  "public_submissions",
592  $this->lng->txt("exc_public_submission"),
593  $this->getSubmissionLink("listPublicSubmissions")
594  );
595  } else {
596  $this->addProperty(
597  self::SEC_SUBMISSION,
598  $this->lng->txt("exc_public_submission"),
599  $this->lng->txt("exc_msg_public_submission")
600  );
601  }
602  }
603 
604  protected function buildFiles(): void
605  {
606  $lng = $this->lng;
607  $ui_factory = $this->gui->ui()->factory();
608  $ui_renderer = $this->gui->ui()->renderer();
609 
610  $ass = $this->ex_ass;
611  $files = $ass->getFiles();
612  if (count($files) > 0) {
613  $cnt = 0;
614  foreach ($files as $file) {
615  $cnt++;
616  // get mime type
617  //$mime = \ilObjMediaObject::getMimeType($file['fullpath']);
618  $mime = $file["mime"] ?? "";
619  $output_filename = htmlspecialchars($file['name'] ?? "");
620 
621  if ($this->media_type->isImage($mime)) {
622  $image = $ui_factory->image()->responsive($file['fullpath'], $output_filename);
623  $glyph_lens = $ui_factory->symbol()->glyph()->enlarge();
624  $button_lens = $ui_factory->button()->standard(
625  $lng->txt("exc_fullscreen"),
626  '#'
627  )->withSymbol($glyph_lens);
628 
629  $modal_page = $ui_factory->modal()->lightboxImagePage($image, $output_filename);
630  $modal = $ui_factory->modal()->lightbox($modal_page);
631 
632  $image = $image->withAction($modal->getShowSignal());
633  $image_lens = $button_lens->withOnClick($modal->getShowSignal());
634 
635  $img_tpl = new \ilTemplate("tpl.image_file.html", true, true, "components/ILIAS/Exercise");
636  $img_tpl->setCurrentBlock("image_content");
637  $img_tpl->setVariable("MODAL", $ui_renderer->render($modal));
638  $img_tpl->setVariable("IMAGE", $ui_renderer->render($image));
639  $img_tpl->setvariable("IMAGE_LENS", $ui_renderer->render($image_lens));
640  $img_tpl->parseCurrentBlock();
641 
642  $this->addProperty(
643  self::SEC_FILES,
644  $output_filename,
645  $img_tpl->get()
646  );
647 
648  } elseif ($this->media_type->isAudio($mime) || $this->media_type->isVideo($mime)) {
649  $media_tpl = new \ilTemplate("tpl.media_file.html", true, true, "components/ILIAS/Exercise");
650 
651  if ($this->media_type->isAudio($mime)) {
652  $p = $ui_factory->player()->audio($file['fullpath']);
653  } else {
654  $p = $ui_factory->player()->video($file['fullpath']);
655  }
656  $media_tpl->setVariable("MEDIA", $ui_renderer->render($p));
657 
658  $but = $ui_factory->button()->shy(
659  $lng->txt("download"),
660  $this->getSubmissionLink("downloadFile", array("file" => urlencode($file["name"])))
661  );
662  $media_tpl->setVariable("DOWNLOAD_BUTTON", $ui_renderer->render($but));
663  $this->addProperty(
664  self::SEC_FILES,
665  $output_filename,
666  $media_tpl->get()
667  );
668  } else {
669  $l = $ui_factory->link()->standard(
670  $lng->txt("download"),
671  $this->getSubmissionLink("downloadFile", array("file" => urlencode($file["name"])))
672  );
673  $this->addProperty(
674  self::SEC_FILES,
675  $output_filename,
676  $ui_renderer->render($l)
677  );
678  }
679  }
680  }
681  }
682 
687  protected function buildSubmission(): void
688  {
689 
690  if (!$this->submission->canView()) {
691  return;
692  }
693 
694  $this->ctrl->setParameterByClass(
695  "ilExSubmissionGUI",
696  "ass_id",
697  $this->assignment->getId()
698  );
699 
700  if ($this->submission->getAssignment()->hasTeam()) {
701  $team_gui = $this->gui->getTeamSubmissionGUI($this->exc, $this->submission);
702  $team_gui->buildSubmissionPropertiesAndActions($this);
703  }
704 
705  $type_gui = $this->types_gui->getById($this->ex_ass->getType());
706  $type_gui->setSubmission($this->submission);
707  $type_gui->setExercise($this->exc);
708  $type_gui->buildSubmissionPropertiesAndActions($this);
709 
710  $last_sub = null;
711  if ($this->submission->hasSubmitted()) {
712  $last_sub = $this->submission->getLastSubmission();
713  if ($last_sub) {
714  $last_sub = \ilDatePresentation::formatDate(new \ilDateTime($last_sub, IL_CAL_DATETIME));
715  $this->addProperty(
716  self::SEC_SUBMISSION,
717  $this->lng->txt("exc_last_submission"),
718  $last_sub
719  );
720  }
721  } else {
722  $this->addProperty(
723  self::SEC_SUBMISSION,
724  $this->lng->txt("exc_last_submission"),
725  $this->lng->txt("exc_no_submission_yet")
726  );
727  }
728 
729  if ($this->exc->getShowSubmissions()) {
730  $this->builPublicSubmissions();
731  }
732  }
733 
734  protected function buildPeerFeedback(): void
735  {
736  if (!$this->submission->canView()) {
737  return;
738  }
739  $peer_review_gui = $this->gui->peerReview()->getPeerReviewGUI(
740  $this->ex_ass,
741  $this->submission
742  );
743  $peer_review_gui->buildSubmissionPropertiesAndActions($this);
744  }
745 
746  protected function buildSampleSolution(): void
747  {
748  $ass = $this->ex_ass;
749  $state = $this->state;
750  $submission = $this->submission;
751 
752  $last_sub = null;
753  if ($submission->hasSubmitted()) {
754  $last_sub = $submission->getLastSubmission();
755  }
756 
757  // global feedback / sample solution
758  if ($ass->getFeedbackDate() === \ilExAssignment::FEEDBACK_DATE_DEADLINE) {
759  $show_global_feedback = ($state->hasSubmissionEndedForAllUsers() && $ass->getFeedbackFile());
760  }
761  //If it is not well configured...(e.g. show solution before deadline)
762  //the user can get the solution before he summit it.
763  //we can check in the elseif $submission->hasSubmitted()
764  elseif ($ass->getFeedbackDate() === \ilExAssignment::FEEDBACK_DATE_CUSTOM) {
765  $show_global_feedback = ($ass->afterCustomDate() && $ass->getFeedbackFile());
766  } else {
767  $show_global_feedback = ($last_sub && $ass->getFeedbackFile());
768  }
769  $this->buildSubmissionFeedback($show_global_feedback);
770  }
771 
772  protected function buildSubmissionFeedback(
773  bool $a_show_global_feedback
774  ): void {
775 
776  $f = $this->gui->ui()->factory();
777  $r = $this->gui->ui()->renderer();
778 
779  $ass = $this->ex_ass;
780  $feedback_id = $this->submission->getFeedbackId();
781  $lng = $this->lng;
782 
783  $feedback_file_manager = $this->domain->assignment()->tutorFeedbackFile($ass->getId());
784  $cnt_files = $feedback_file_manager->count($this->user_id);
785 
786 
787  $lpcomment = $ass->getMemberStatus()->getComment();
788  $mark = $ass->getMemberStatus()->getMark();
789  $status = $ass->getMemberStatus()->getStatus();
790 
791  if ($lpcomment != "" ||
792  $mark != "" ||
793  $status !== "notgraded" ||
794  $cnt_files > 0 ||
795  $a_show_global_feedback) {
796 
797  if ($lpcomment !== "") {
798  $this->addProperty(
799  self::SEC_TUTOR_EVAL,
800  $lng->txt("exc_comment"),
801  nl2br($lpcomment)
802  );
803  }
804  if ($mark !== "") {
805  $this->addProperty(
806  self::SEC_TUTOR_EVAL,
807  $lng->txt("exc_mark"),
808  $mark
809  );
810  }
811 
812  if ($status !== "" && $status !== "notgraded") {
813  $this->addProperty(
814  self::SEC_TUTOR_EVAL,
815  $lng->txt("status"),
816  $lng->txt("exc_" . $status)
817  );
818  }
819 
820  if ($cnt_files > 0) {
821  $files = $feedback_file_manager->getFiles($this->user_id);
822  foreach ($files as $file) {
823  $link = $f->link()->standard(
824  $lng->txt("download"),
825  $this->getSubmissionLink("downloadFeedbackFile", array("file" => urlencode($file)))
826  );
827  $this->addProperty(
828  self::SEC_TUTOR_EVAL,
829  $file,
830  $r->render($link)
831  );
832  }
833  }
834 
835  // #15002 - global feedback
836  if ($a_show_global_feedback) {
837  $link = $f->link()->standard(
838  $lng->txt("download"),
839  $this->getSubmissionLink("downloadGlobalFeedbackFile")
840  );
841  $this->addProperty(
842  self::SEC_SAMPLE_SOLUTION,
843  $ass->getFeedbackFile(),
844  $r->render($link)
845  );
846  }
847  }
848  }
849 
854  protected function getTimeString(int $a_deadline): string
855  {
856  $lng = $this->lng;
857 
858  if ($a_deadline == 0) {
859  return $lng->txt("exc_submit_convenience_no_deadline");
860  }
861 
862  if ($a_deadline - time() <= 0) {
863  $time_str = $lng->txt("exc_time_over_short");
864  } else {
865  $time_str = \ilLegacyFormElementsUtil::period2String(new \ilDateTime($a_deadline, IL_CAL_UNIX));
866  }
867 
868  return $time_str;
869  }
870 
871  protected function getSubmissionLink(
872  string $a_cmd,
873  ?array $a_params = null
874  ): string {
875  $ilCtrl = $this->ctrl;
876 
877  if (is_array($a_params)) {
878  foreach ($a_params as $name => $value) {
879  $ilCtrl->setParameterByClass("ilexsubmissiongui", $name, $value);
880  }
881  }
882 
883  $ilCtrl->setParameterByClass("ilexsubmissiongui", "ass_id", $this->assignment->getId());
884  $url = $ilCtrl->getLinkTargetByClass([\ilAssignmentPresentationGUI::class, "ilexsubmissiongui"], $a_cmd);
885  $ilCtrl->setParameterByClass("ilexsubmissiongui", "ass_id", "");
886 
887  if (is_array($a_params)) {
888  foreach ($a_params as $name => $value) {
889  $ilCtrl->setParameterByClass("ilexsubmissiongui", $name, "");
890  }
891  }
892 
893  return $url;
894  }
895 
899  protected function getIconForStatus(string $status, int $variant = \ilLPStatusIcons::ICON_VARIANT_LONG): string
900  {
901  $icons = \ilLPStatusIcons::getInstance($variant);
902  $lng = $this->lng;
903 
904  switch ($status) {
905  case "passed":
906  return $icons->renderIcon(
907  $icons->getImagePathCompleted(),
908  $lng->txt("exc_" . $status)
909  );
910 
911  case "failed":
912  return $icons->renderIcon(
913  $icons->getImagePathFailed(),
914  $lng->txt("exc_" . $status)
915  );
916 
917  default:
918  return $icons->renderIcon(
919  $icons->getImagePathNotAttempted(),
920  $lng->txt("exc_" . $status)
921  );
922  }
923  }
924 }
Exercise UI frontend presentation service class.
const IL_CAL_DATETIME
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...
static period2String(ilDateTime $a_from, $a_to=null)
Return a string of time period.
static getInstance(int $variant=ilLPStatusIcons::ICON_VARIANT_DEFAULT, ?\ILIAS\UI\Renderer $renderer=null, ?\ILIAS\UI\Factory $factory=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ILIAS MediaObjects MediaType MediaTypeManager $media_type
setParameterByClass(string $a_class, string $a_parameter, $a_value)
$url
Definition: shib_logout.php:66
const IL_CAL_UNIX
getIconForStatus(string $status, int $variant=\ilLPStatusIcons::ICON_VARIANT_LONG)
Get the rendered icon for a status (failed, passed or not graded).
getSections(bool $include_schedule=true, bool $overview=false)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
info()
description: > Example for rendering a info message box.
Definition: info.php:34
This describes a standard button.
Definition: Primary.php:26
Class ilObjExercise.
addProperty(string $section, string $prop, string $val)
__construct(\ilObjExercise $exc, MandatoryAssignmentsManager $mandatory_manager, InternalDomainService $domain_service, InternalGUIService $gui_service)
global $DIC
Definition: shib_login.php:22
static getInstanceByIds(int $a_ass_id, int $a_user_id=0)
$txt
Definition: error.php:31
addAction(string $section, Component $button_or_link)
setHeadProperty(string $type, string $prop, string $val)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
getTimeString(int $a_deadline)
Get time string for deadline.
$r