ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
PropertyAndActionBuilderUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use ILIAS\UI\Component\Button\Shy as ButtonShy;
27use ILIAS\UI\Component\Link\Standard as LinkStandard;
28use 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(
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 {
160 return $this->additional_head_properties;
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 {
175 return $this->instructions_hidden;
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;
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()) {
268 $this->addAdditionalHeadProperty(
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)
311 $this->addAdditionalHeadProperty(
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) {
356 $this->addAdditionalHeadProperty(
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
494 $schedule = $info->getScheduleInfo();
495 $ilCtrl = $this->ctrl;
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 {
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();
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($this->gui->html()->escapeCurly($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 {
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 {
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);
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}
factory()
addProperty(string $section, string $prop, string $val)
getTimeString(int $a_deadline)
Get time string for deadline.
setHeadProperty(string $type, string $prop, string $val)
ILIAS MediaObjects MediaType MediaTypeManager $media_type
__construct(\ilObjExercise $exc, MandatoryAssignmentsManager $mandatory_manager, InternalDomainService $domain_service, InternalGUIService $gui_service)
addAction(string $section, Component $button_or_link)
getSections(bool $include_schedule=true, bool $overview=false)
getIconForStatus(string $status, int $variant=\ilLPStatusIcons::ICON_VARIANT_LONG)
Get the rendered icon for a status (failed, passed or not graded).
Exercise UI frontend presentation service class.
const IL_CAL_UNIX
const IL_CAL_DATETIME
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
static getInstanceByIds(int $a_ass_id, int $a_user_id=0)
static getInstance(int $variant=ilLPStatusIcons::ICON_VARIANT_DEFAULT, ?\ILIAS\UI\Renderer $renderer=null, ?\ILIAS\UI\Factory $factory=null)
static period2String(ilDateTime $a_from, $a_to=null)
Return a string of time period.
Class ilObjExercise.
$info
Definition: entry_point.php:21
$txt
Definition: error.php:31
This describes a standard button.
Definition: Primary.php:27
A component is the most general form of an entity in the UI.
Definition: Component.php:28
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68