ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilExSubmission.php
Go to the documentation of this file.
1<?php
2
20
29{
30 public const TYPE_FILE = "File";
31 public const TYPE_OBJECT = "Object"; // Blogs in WSP/Portfolio
32 public const TYPE_TEXT = "Text";
33 public const TYPE_REPO_OBJECT = "RepoObject"; // Wikis
34 protected \ILIAS\Exercise\Submission\SubmissionManager $sub_manager;
35 protected \ILIAS\Exercise\InternalDomainService $domain;
36
37 protected ilObjUser $user;
38 protected ilDBInterface $db;
39 protected ilLanguage $lng;
40 protected ilCtrl $ctrl;
42 protected int $user_id;
43 protected ?ilExAssignmentTeam $team = null;
44 protected ?ilExPeerReview $peer_review = null;
45 protected bool $is_tutor;
46 protected bool $public_submissions;
50 private \ilGlobalTemplateInterface $main_tpl;
51
52 public function __construct(
53 ilExAssignment $a_ass,
54 int $a_user_id,
55 ?ilExAssignmentTeam $a_team = null, // did not find any place that sets this....
56 bool $a_is_tutor = false,
57 bool $a_public_submissions = false
58 ) {
59 global $DIC;
60 $this->main_tpl = $DIC->ui()->mainTemplate();
61
62 $this->user = $DIC->user();
63 $this->db = $DIC->database();
64 $this->lng = $DIC->language();
65 $this->ctrl = $DIC->ctrl();
66
67 $this->assignment = $a_ass;
68 $this->ass_type = $this->assignment->getAssignmentType();
69 $this->ass_types = ilExAssignmentTypes::getInstance();
70
71 $this->user_id = $a_user_id;
72 $this->is_tutor = $a_is_tutor;
73 $this->public_submissions = $a_public_submissions;
74
75 $this->state = ilExcAssMemberState::getInstanceByIds($a_ass->getId(), $a_user_id);
76
77 if ($a_ass->hasTeam()) { // ass type uses teams...
78 if (!$a_team) {
79 // this might be a team with no id (since the create on demand parameter is not set)
80 $this->team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $this->user_id);
81 } else {
82 $this->team = $a_team;
83 }
84 }
85
86 if ($this->assignment->getPeerReview()) {
87 $this->peer_review = new ilExPeerReview($this->assignment);
88 }
89 $this->domain = $DIC->exercise()->internal()->domain();
90 $this->sub_manager = $DIC->exercise()->internal()->domain()->submission(
91 $a_ass->getId()
92 );
93 }
94
95 public function getSubmissionType(): string
96 {
97 return $this->assignment->getAssignmentType()->getSubmissionType();
98 }
99
100 public function getAssignment(): ilExAssignment
101 {
102 return $this->assignment;
103 }
104
105 public function getTeam(): ?ilExAssignmentTeam
106 {
107 return $this->team;
108 }
109
110 public function getPeerReview(): ?ilExPeerReview
111 {
112 return $this->peer_review;
113 }
114
115 public function validatePeerReviews(): array
116 {
117 $res = array();
118 foreach ($this->getUserIds() as $user_id) {
119 $valid = true;
120
121 // no peer review == valid
122 if ($this->peer_review) {
123 $valid = $this->peer_review->isFeedbackValidForPassed($user_id);
124 }
125
127 }
128 return $res;
129 }
130
131 public function getUserId(): int
132 {
133 return $this->user_id;
134 }
135
136 public function getUserIds(): array
137 {
138 if ($this->team &&
139 !$this->hasNoTeamYet()) {
140 return $this->team->getMembers();
141 }
142
143 // if has no team currently there still might be uploads attached
144 return array($this->user_id);
145 }
146
150 public function getFeedbackId(): string
151 {
152 if ($this->team) {
153 return "t" . $this->team->getId();
154 } else {
155 return (string) $this->getUserId();
156 }
157 }
158
159 public function hasSubmitted(): bool
160 {
161 return (bool) $this->sub_manager->getSubmissionsOfUser(
162 $this->getUserId(),
163 null,
164 true
165 )->current();
166 }
167
168 public function hasSubmittedPrintVersion(): bool
169 {
170 return ($this->getSubmittedEntry(true)?->getRid() != "");
171 }
172
173 public function getSubmittedEntry(bool $print = false): ?Submission
174 {
175 return $this->sub_manager->getSubmissionsOfUser(
176 $this->getUserId(),
177 null,
178 false,
179 null,
180 $print
181 )->current();
182 }
183
184 public function getSelectedObject(): ?Submission
185 {
186 return $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
187 }
188
189 public function canSubmit(): bool
190 {
191 return ($this->isOwner() &&
192 $this->state->isSubmissionAllowed());
193 }
194
195 public function canView(): bool
196 {
197 $ilUser = $this->user;
198
199 if ($this->canSubmit() ||
200 $this->isTutor() ||
201 $this->isInTeam() ||
202 $this->public_submissions) {
203 return true;
204 }
205
206 // #16115
207 if ($this->peer_review) {
208 // peer review givers may view peer submissions
209 foreach ($this->peer_review->getPeerReviewsByPeerId($this->getUserId()) as $giver) {
210 if ($giver["giver_id"] == $ilUser->getId()) {
211 return true;
212 }
213 }
214 }
215
216 return false;
217 }
218
219 public function isTutor(): bool
220 {
221 return $this->is_tutor;
222 }
223
224 public function hasNoTeamYet(): bool
225 {
226 if ($this->assignment->hasTeam() &&
227 !$this->team->getId()) {
228 return true;
229 }
230 return false;
231 }
232
233 public function isInTeam(?int $a_user_id = null): bool
234 {
235 $ilUser = $this->user;
236
237 if (!$a_user_id) {
238 $a_user_id = $ilUser->getId();
239 }
240 return in_array($a_user_id, $this->getUserIds());
241 }
242
243 public function isOwner(): bool
244 {
245 $ilUser = $this->user;
246
247 return ($ilUser->getId() == $this->getUserId());
248 }
249
250 public function hasPeerReviewAccess(): bool
251 {
252 return ($this->peer_review &&
253 $this->peer_review->hasPeerReviewAccess($this->user_id));
254 }
255
256 public function canAddFile(): bool
257 {
258 if (!$this->canSubmit()) {
259 return false;
260 }
261
262 $max = $this->getAssignment()->getMaxFile();
263 $cnt_sub = $this->sub_manager->countSubmissionsOfUser(
264 $this->getUserId()
265 );
266 if ($max &&
267 $max <= $cnt_sub) {
268 return false;
269 }
270
271 return true;
272 }
273
274
275 //
276 // FILES
277 //
278
279 public function isLate(): bool
280 {
281 $dl = $this->state->getOfficialDeadline();
282 //$dl = $this->assignment->getPersonalDeadline($this->getUserId());
283 return ($dl && $dl < time());
284 }
285
286 protected function getStorageId(): int
287 {
288 if ($this->ass_type->isSubmissionAssignedToTeam()) {
289 $storage_id = $this->getTeam()->getId();
290 } else {
291 $storage_id = $this->getUserId();
292 }
293 return $storage_id;
294 }
295
300 public function lookupNewFiles(
301 ?int $a_tutor = null
302 ): array {
303 $ilDB = $this->db;
304 $ilUser = $this->user;
305
306 $tutor = ($a_tutor)
307 ?: $ilUser->getId();
308
309 $where = " AND " . $this->getTableUserWhere();
310
311 $q = "SELECT exc_returned.returned_id AS id " .
312 "FROM exc_usr_tutor, exc_returned " .
313 "WHERE exc_returned.ass_id = exc_usr_tutor.ass_id " .
314 " AND exc_returned.user_id = exc_usr_tutor.usr_id " .
315 " AND exc_returned.ass_id = " . $ilDB->quote($this->getAssignment()->getId(), "integer") .
316 $where .
317 " AND exc_usr_tutor.tutor_id = " . $ilDB->quote($tutor, "integer") .
318 " AND exc_usr_tutor.download_time < exc_returned.ts ";
319
320 $new_up_set = $ilDB->query($q);
321
322 $new_up = array();
323 while ($new_up_rec = $ilDB->fetchAssoc($new_up_set)) {
324 $new_up[] = $new_up_rec["id"];
325 }
326
327 return $new_up;
328 }
329
333 public static function lookupExerciseIdForReturnedId(
334 int $a_returned_id
335 ): int {
336 global $DIC;
337
338 $ilDB = $DIC->database();
339
340 $set = $ilDB->query("SELECT obj_id" .
341 " FROM exc_returned" .
342 " WHERE returned_id = " . $ilDB->quote($a_returned_id, "integer"));
343 $row = $ilDB->fetchAssoc($set);
344 return (int) $row["obj_id"];
345 }
346
351 public static function findUserFiles(
352 int $a_user_id,
353 string $a_filetitle
354 ): array {
355 global $DIC;
356
357 $ilDB = $DIC->database();
358
359 $set = $ilDB->query("SELECT obj_id, ass_id" .
360 " FROM exc_returned" .
361 " WHERE user_id = " . $ilDB->quote($a_user_id, "integer") .
362 " AND filetitle = " . $ilDB->quote($a_filetitle, "text"));
363 $res = array();
364 while ($row = $ilDB->fetchAssoc($set)) {
365 $res[$row["ass_id"]] = $row;
366 }
367 return $res;
368 }
369
370 public function deleteAllFiles(): void
371 {
372 $this->sub_manager->deleteAllSubmissionsOfUser($this->getUserId());
373 }
374
379 /* --> use manager deleteSubmissions()
380 public function deleteSelectedFiles(
381 array $file_id_array
382 ): void {
383 $ilDB = $this->db;
384
385
386 $where = " AND " . $this->getTableUserWhere(true);
387
388
389 if ($file_id_array === []) {
390 return;
391 }
392
393 if ($file_id_array !== []) {
394 $result = $ilDB->query("SELECT * FROM exc_returned" .
395 " WHERE " . $ilDB->in("returned_id", $file_id_array, false, "integer") .
396 $where);
397
398 if ($ilDB->numRows($result)) {
399 $result_array = array();
400 while ($row = $ilDB->fetchAssoc($result)) {
401 $row["timestamp"] = $row["ts"];
402 $result_array[] = $row;
403 }
404
405 // delete the entries in the database
406 $ilDB->manipulate("DELETE FROM exc_returned" .
407 " WHERE " . $ilDB->in("returned_id", $file_id_array, false, "integer") .
408 $where);
409
410 // delete the files
411 $path = $this->initStorage()->getAbsoluteSubmissionPath();
412 foreach ($result_array as $value) {
413 if ($value["filename"]) {
414 if ($this->team) {
415 $this->team->writeLog(
416 ilExAssignmentTeam::TEAM_LOG_REMOVE_FILE,
417 $value["filetitle"]
418 );
419 }
420
421 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
422 $storage_id = $value["team_id"];
423 } else {
424 $storage_id = $value["user_id"];
425 }
426
427 $filename = $path . "/" . $storage_id . "/" . basename($value["filename"]);
428 if (file_exists($filename)) {
429 unlink($filename);
430 }
431 }
432 }
433 }
434 }
435 }*/
436
441 public static function deleteUser(
442 int $a_exc_id,
443 int $a_user_id
444 ): void {
445 global $DIC;
446
447 $db = $DIC->database();
448
449 foreach (ilExAssignment::getInstancesByExercise($a_exc_id) as $ass) {
450 $submission = new self($ass, $a_user_id);
451 $submission->deleteAllFiles();
452
453 // remove from any team
454 $team = $submission->getTeam();
455 if ($team) {
456 $team->removeTeamMember($a_user_id);
457 }
458
459 // #14900
460 if (\ilObject::_lookupType($ass->getExerciseId()) === "exc") { // see #45183
461 $member_status = $ass->getMemberStatus($a_user_id);
462 $member_status->setStatus("notgraded");
463 $member_status->update();
464 }
465
466 $db->manipulateF(
467 "DELETE FROM exc_usr_tutor " .
468 "WHERE ass_id = %s AND usr_id = %s",
469 array("integer", "integer"),
470 array($ass->getId(), $a_user_id)
471 );
472 }
473 }
474
479 protected function getLastDownloadTime(
480 array $a_user_ids
481 ): string {
482 $ilDB = $this->db;
483 $ilUser = $this->user;
484
485 $q = "SELECT download_time FROM exc_usr_tutor WHERE " .
486 " ass_id = " . $ilDB->quote($this->getAssignment()->getId(), "integer") . " AND " .
487 $ilDB->in("usr_id", $a_user_ids, "", "integer") . " AND " .
488 " tutor_id = " . $ilDB->quote($ilUser->getId(), "integer") .
489 " ORDER BY download_time DESC";
490 $lu_set = $ilDB->query($q);
491 $lu_rec = $ilDB->fetchAssoc($lu_set);
492 return $lu_rec["download_time"] ?? "";
493 }
494
495 public function downloadFiles(
496 ?array $a_file_ids = null,
497 bool $a_only_new = false,
498 bool $a_peer_review_mask_filename = false
499 ): bool {
500 $ilUser = $this->user;
502
503 $user_ids = $this->getUserIds();
504 $is_team = $this->assignment->hasTeam();
505 // get last download time
506 $download_time = null;
507 if ($a_only_new) {
508 $download_time = $this->getLastDownloadTime($user_ids);
509 }
510
511 if ($this->is_tutor) {
512 $this->updateTutorDownloadTime();
513 }
514
515 if ($a_peer_review_mask_filename) {
516 // process peer review sequence id
517 $peer_id = null;
518 foreach ($this->peer_review->getPeerReviewsByGiver($ilUser->getId()) as $idx => $item) {
519 if ($item["peer_id"] == $this->getUserId()) {
520 $peer_id = $idx + 1;
521 break;
522 }
523 }
524 // this will remove personal info from zip-filename
525 $is_team = true;
526 }
527
528 $subs = iterator_to_array($this->sub_manager->getSubmissionsOfUser(
529 $this->getUserId(),
530 $a_file_ids,
531 false,
532 $download_time
533 ));
534
535 if (count($subs) > 0) {
536 if (count($subs) == 1) {
538 $sub = current($subs);
539
540 $title = $sub->getTitle();
541
542 switch ($this->assignment->getType()) {
545 $name = ilObjUser::_lookupName($sub->getUserId());
546 $title = ilObject::_lookupTitle($this->assignment->getExerciseId()) . " - " .
547 $this->assignment->getTitle() . " - " .
548 $name["firstname"] . " " .
549 $name["lastname"] . " (" .
550 $name["login"] . ").zip";
551 break;
552
553 // @todo: generalize
555 $title = ilObject::_lookupTitle($this->assignment->getExerciseId()) . " - " .
556 $this->assignment->getTitle() . " (Team " . $this->getTeam()->getId() . ").zip";
557 break;
558
559 default:
560 break;
561 }
562
563 if ($a_peer_review_mask_filename) {
564 $title_a = explode(".", $sub->getTitle());
565 $suffix = array_pop($title_a);
566 $title = $this->assignment->getTitle() . "_peer" . $peer_id . "." . $suffix;
567 } elseif ($sub->getLate()) {
568 $title = $lng->txt("exc_late_submission") . " - " .
569 $title;
570 }
571
572 $this->downloadSingleFile($sub, $title);
573 } else {
574 $this->sub_manager->deliverSubmissions(
575 $subs,
576 $this->getUserId(),
577 $a_peer_review_mask_filename,
578 $peer_id ?? 0
579 );
580 }
581 } else {
582 return false;
583 }
584
585 return true;
586 }
587
588 // Update the timestamp of the last download of current user (=tutor)
589 public function updateTutorDownloadTime(): void
590 {
591 $ilUser = $this->user;
592 $ilDB = $this->db;
593
594 $exc_id = $this->assignment->getExerciseId();
595 $ass_id = $this->assignment->getId();
596
597 foreach ($this->getUserIds() as $user_id) {
598 $ilDB->manipulateF(
599 "DELETE FROM exc_usr_tutor " .
600 "WHERE ass_id = %s AND usr_id = %s AND tutor_id = %s",
601 array("integer", "integer", "integer"),
602 array($ass_id, $user_id, $ilUser->getId())
603 );
604
605 $ilDB->manipulateF(
606 "INSERT INTO exc_usr_tutor (ass_id, obj_id, usr_id, tutor_id, download_time) VALUES " .
607 "(%s, %s, %s, %s, %s)",
608 array("integer", "integer", "integer", "integer", "timestamp"),
609 array($ass_id, $exc_id, $user_id, $ilUser->getId(), ilUtil::now())
610 );
611 }
612 }
613
614 protected function downloadSingleFile(
615 Submission $sub,
616 string $title
617 ): void {
618 $this->domain->submission($this->assignment->getId())->deliverFile(
619 $sub->getUserId(),
620 $sub->getRid(),
621 $title
622 );
623 }
624
625 // Get user/team where clause
626 public function getTableUserWhere(): string
627 {
628 $ilDB = $this->db;
629
630 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
631 $team_id = $this->getTeam()->getId();
632 $where = " team_id = " . $ilDB->quote($team_id, "integer") . " ";
633 } else {
634 $where = " " . $ilDB->in("user_id", $this->getUserIds(), "", "integer") . " ";
635 }
636 return $where;
637 }
638
639
644 public function getLastSubmission(): ?string
645 {
646 $ilDB = $this->db;
647
648 $ilDB->setLimit(1, 0);
649
650 $q = "SELECT obj_id,user_id,ts FROM exc_returned" .
651 " WHERE ass_id = " . $ilDB->quote($this->assignment->getId(), "integer") .
652 " AND " . $this->getTableUserWhere() .
653 " AND (filename IS NOT NULL OR atext IS NOT NULL)" .
654 " AND ts IS NOT NULL" .
655 " ORDER BY ts DESC";
656 $usr_set = $ilDB->query($q);
657 $array = $ilDB->fetchAssoc($usr_set);
658 return ($array["ts"] ?? null);
659 }
660
665 public function getLastOpeningHTMLView(): ?string
666 {
667 $this->db->setLimit(1, 0);
668
669 $q = "SELECT web_dir_access_time FROM exc_returned" .
670 " WHERE ass_id = " . $this->db->quote($this->assignment->getId(), "integer") .
671 " AND (filename IS NOT NULL OR atext IS NOT NULL)" .
672 " AND web_dir_access_time IS NOT NULL" .
673 " AND " . $this->getTableUserWhere() .
674 " ORDER BY web_dir_access_time DESC";
675
676 $res = $this->db->query($q);
677
678 $data = $this->db->fetchAssoc($res);
679
680 return $data["web_dir_access_time"] ?? null;
681 }
682
683
684 //
685 // OBJECTS
686 //
687
693 public function addResourceObject(
694 string $a_wsp_id, // note: text assignments currently call this with "TEXT"
695 ?string $a_text = null
696 ): int {
697 $ilDB = $this->db;
698
699 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
700 $user_id = 0;
701 $team_id = $this->getTeam()->getId();
702 } else {
703 $user_id = $this->getUserId();
704 $team_id = 0;
705 }
706
707 // repository objects must be unique in submissions
708 // the same repo object cannot be used in different submissions or even different assignment/exercises
709 // why? -> the access handling would fail, since the access depends e.g. on teams or even phase of the
710 // assignment
711 if ($this->getAssignment()->getAssignmentType()->getSubmissionType() == ilExSubmission::TYPE_REPO_OBJECT) {
712 $repos_ass_type_ids = $this->ass_types->getIdsForSubmissionType(ilExSubmission::TYPE_REPO_OBJECT);
713 $subs = $this->getSubmissionsForFilename($a_wsp_id, $repos_ass_type_ids);
714 if ($subs !== []) {
715 throw new ilExerciseException("Repository object $a_wsp_id is already assigned to another assignment.");
716 }
717 }
718
719 $next_id = $ilDB->nextId("exc_returned");
720 $query = sprintf(
721 "INSERT INTO exc_returned " .
722 "(returned_id, obj_id, user_id, filetitle, ass_id, ts, atext, late, team_id) " .
723 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)",
724 $ilDB->quote($next_id, "integer"),
725 $ilDB->quote($this->assignment->getExerciseId(), "integer"),
726 $ilDB->quote($user_id, "integer"),
727 $ilDB->quote($a_wsp_id, "text"),
728 $ilDB->quote($this->assignment->getId(), "integer"),
729 $ilDB->quote(ilUtil::now(), "timestamp"),
730 $ilDB->quote($a_text, "text"),
731 $ilDB->quote($this->isLate(), "integer"),
732 $ilDB->quote($team_id, "integer")
733 );
734 $ilDB->manipulate($query);
735
736 return $next_id;
737 }
738
739 /*
740 * Remove ressource from assignement (and delete
741 * its submission): Note: The object itself will not be deleted.
742 */
743 public function deleteResourceObject(): void
744 {
745 $this->deleteAllFiles();
746 }
747
753 public function updateTextSubmission(string $a_text): ?int
754 {
755 $ilDB = $this->db;
756
757 // no text = remove submission
758 if (!trim($a_text)) {
759 $this->sub_manager->deleteAllSubmissionsOfUser($this->getUserId());
760 return null;
761 }
762
763 $sub = $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
764
765 if (!$sub) {
766 return $this->addResourceObject("TEXT", $a_text);
767 } else {
768 $id = $sub->getId();
769 if ($id) {
770 $ilDB->manipulate("UPDATE exc_returned" .
771 " SET atext = " . $ilDB->quote($a_text, "text") .
772 ", ts = " . $ilDB->quote(ilUtil::now(), "timestamp") .
773 ", late = " . $ilDB->quote($this->isLate(), "integer") .
774 " WHERE returned_id = " . $ilDB->quote($id, "integer"));
775 return $id;
776 }
777 }
778 return null;
779 }
780
781 //
782 // GUI helper
783 //
784
788 public function getDownloadedFilesInfoForTableGUIS(): array
789 {
791 $ilCtrl = $this->ctrl;
792
793 $result = array();
794 $result["files"]["count"] = "---";
795
796 // submission:
797 // see if files have been resubmmited after solved
798 $last_sub = $this->getLastSubmission();
799 if ($last_sub) {
800 $last_sub = ilDatePresentation::formatDate(new ilDateTime($last_sub, IL_CAL_DATETIME));
801 } else {
802 $last_sub = "---";
803 }
804 $result["last_submission"]["txt"] = $lng->txt("exc_last_submission");
805 $result["last_submission"]["value"] = $last_sub;
806
807 // #16994
808 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", $this->getUserId());
809
810 // assignment type specific
811 switch ($this->assignment->getType()) {
813 // data is merged by team - see above
814 // fallthrough
815
817 $subs = $this->sub_manager->getSubmissionsOfUser($this->getUserId());
818 $late_files = 0;
819 $cnt_all = 0;
820 foreach ($subs as $sub) {
821 if ($sub->getLate()) {
822 $late_files++;
823 }
824 $cnt_all++;
825 }
826
827 // nr of submitted files
828 $result["files"]["txt"] = $lng->txt("exc_files_returned");
829 if ($late_files !== 0) {
830 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . " (" . $late_files . ")</span>";
831 }
832 $sub_cnt = $cnt_all;
833 $new = $this->lookupNewFiles();
834 if ($new !== []) {
835 $sub_cnt .= " " . sprintf($lng->txt("cnt_new"), count($new));
836 }
837
838 $result["files"]["count"] = $sub_cnt;
839
840 // download command
841 if ($sub_cnt > 0) {
842 $result["files"]["download_url"] =
843 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
844
845 if (count($new) <= 0) {
846 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
847 } else {
848 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_all_files");
849 }
850
851 // download new files only
852 if ($new !== []) {
853 $result["files"]["download_new_url"] =
854 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadNewReturned");
855
856 $result["files"]["download_new_txt"] = $lng->txt("exc_tbl_action_download_new_files");
857 }
858 }
859 break;
860
862 $result["files"]["txt"] = $lng->txt("exc_blog_returned");
864 $sub = $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
865 if ($sub) {
866 if ($sub->getRid() != "") {
867 if ($sub->getLate()) {
868 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
869 }
870
871 $result["files"]["count"] = 1;
872
873 $result["files"]["download_url"] =
874 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
875
876 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
877 }
878 }
879 break;
880
882 $result["files"]["txt"] = $lng->txt("exc_portfolio_returned");
884 $sub = $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
885 if ($sub) {
886 if ($sub->getRid() != "") {
887 if ($sub->getLate()) {
888 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
889 }
890
891 $result["files"]["count"] = 1;
892
893 $result["files"]["download_url"] =
894 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
895
896 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
897 }
898 }
899 break;
900
902 $result["files"]["txt"] = $lng->txt("exc_files_returned_text");
903 $sub = $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
904 if ($sub) {
905 $result["files"]["count"] = 1;
906
907 if (trim($sub->getText()) !== '' && trim($sub->getText()) !== '0') {
908 if ($sub->getLate()) {
909 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
910 }
911
912 $result["files"]["download_url"] =
913 $ilCtrl->getLinkTargetByClass("ilexsubmissiontextgui", "showAssignmentText");
914
915 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_text_assignment_show");
916 }
917 }
918 break;
919
921 $result["files"]["txt"] = $lng->txt("exc_wiki_returned");
922 $sub = $this->sub_manager->getSubmissionsOfUser($this->getUserId())->current();
923 if ($sub) {
924 if ($sub->getRid() != "") {
925 if ($sub->getLate()) {
926 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
927 }
928
929 $result["files"]["count"] = 1;
930
931 $result["files"]["download_url"] =
932 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
933
934 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
935 }
936 }
937 break;
938 }
939
940 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", "");
941
942 return $result;
943 }
944
948 public static function getSubmissionsForFilename(
949 string $a_filename,
950 array $a_assignment_types = array()
951 ): array {
952 global $DIC;
953
954 $db = $DIC->database();
955
956 $query = "SELECT * FROM exc_returned r LEFT JOIN exc_assignment a" .
957 " ON (r.ass_id = a.id) " .
958 " WHERE r.filetitle = " . $db->quote($a_filename, "string");
959
960 if (is_array($a_assignment_types) && $a_assignment_types !== []) {
961 $query .= " AND " . $db->in("a.type", $a_assignment_types, false, "integer");
962 }
963
964 $set = $db->query($query);
965 $rets = array();
966 while ($rec = $db->fetchAssoc($set)) {
967 $rets[] = $rec;
968 }
969
970
971 return $rets;
972 }
973
977 public static function getDirectoryNameFromUserData(int $a_user_id): string
978 {
979 $userName = ilObjUser::_lookupName($a_user_id);
981 trim($userName["lastname"]) . "_" .
982 trim($userName["firstname"]) . "_" .
983 trim($userName["login"]) . "_" .
984 $userName["user_id"]
985 );
986 }
987
988 public static function getAssignmentParticipants(
989 int $a_exercise_id,
990 int $a_ass_id
991 ): array {
992 global $DIC;
993
994 $ilDB = $DIC->database();
995
996 $participants = array();
997 $query = "SELECT user_id FROM exc_returned WHERE ass_id = " .
998 $ilDB->quote($a_ass_id, "integer") .
999 " AND obj_id = " .
1000 $ilDB->quote($a_exercise_id, "integer");
1001
1002 $res = $ilDB->query($query);
1003
1004 while ($row = $ilDB->fetchAssoc($res)) {
1005 $participants[] = $row['user_id'];
1006 }
1007
1008 return $participants;
1009 }
1010
1011 public static function processZipFile(
1012 string $a_directory,
1013 string $a_file,
1014 bool $structure
1015 ): void {
1016 global $DIC;
1017
1018 $lng = $DIC->language();
1019
1020 $pathinfo = pathinfo($a_file);
1021 $file = $pathinfo["basename"];
1022
1023 // see 22727
1024 if (($pathinfo["extension"] ?? '') === '') {
1025 $file .= ".zip";
1026 }
1027
1028 // Copy zip-file to new directory, unzip and remove it
1029 // TODO: check archive for broken file
1030 //copy ($a_file, $a_directory . "/" . $file);
1031 ilFileUtils::moveUploadedFile($a_file, $file, $a_directory . "/" . $file);
1032 $DIC->legacyArchives()->unzip(
1033 $a_directory . "/" . $file,
1034 null,
1035 false,
1036 true,
1037 false
1038 );
1039 unlink($a_directory . "/" . $file);
1040 //echo "-".$a_directory . "/" . $file."-";
1041 // Stores filename and paths into $filearray to check for viruses
1042 // Checks if filenames can be read, else -> throw exception and leave
1043 $filearray = [];
1044 ilFileUtils::recursive_dirscan($a_directory, $filearray);
1045
1046 // if there are no files unziped (->broken file!)
1047 if (empty($filearray)) {
1048 throw new ilFileUtilsException(
1049 $lng->txt("archive_broken"),
1051 );
1052 }
1053
1054 // virus handling
1055 foreach ($filearray["file"] as $key => $value) {
1056 // remove "invisible" files
1057 if (substr($value, 0, 1) == "." || stristr(
1058 $filearray["path"][$key],
1059 "/__MACOSX/"
1060 )) {
1061 unlink($filearray["path"][$key] . $value);
1062 unset($filearray["path"][$key]);
1063 unset($filearray["file"][$key]);
1064 continue;
1065 }
1066
1067 $vir = ilVirusScanner::virusHandling($filearray["path"][$key], $value);
1068 if (!$vir[0]) {
1069 // Unlink file and throw exception
1070 unlink($filearray['path'][$key]);
1071 throw new ilFileUtilsException(
1072 $lng->txt("file_is_infected") . "<br />" . $vir[1],
1074 );
1075 } elseif ($vir[1] != "") {
1076 throw new ilFileUtilsException(
1077 $vir[1],
1079 );
1080 }
1081 }
1082
1083 // If archive is to be used "flat"
1084 $doublettes = '';
1085 if (!$structure) {
1086 foreach (array_count_values($filearray["file"]) as $key => $value) {
1087 // Archive contains same filenames in different directories
1088 if ($value != "1") {
1089 $doublettes .= " '" . ilFileUtils::utf8_encode($key) . "'";
1090 }
1091 }
1092 if (strlen($doublettes) > 0) {
1093 throw new ilFileUtilsException(
1094 $lng->txt("exc_upload_error") . "<br />" . $lng->txt(
1095 "zip_structure_error"
1096 ) . $doublettes,
1098 );
1099 }
1100 } else {
1101 $mac_dir = $a_directory . "/__MACOSX";
1102 if (file_exists($mac_dir)) {
1103 ilFileUtils::delDir($mac_dir);
1104 }
1105 }
1106 }
1107}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$structure
TOTAL STRUCTURE.
const IL_CAL_DATETIME
Class ilCtrl provides processing control methods.
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
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByUserId(int $a_assignment_id, int $a_user_id, bool $a_create_on_demand=false)
removeTeamMember(int $a_user_id, ?int $a_exc_ref_id=null)
Exercise assignment.
static getInstancesByExercise(int $a_exc_id)
const TYPE_UPLOAD
direct checks against const should be avoided, use type objects instead
Exercise peer review.
Exercise submission //TODO: This class has many static methods related to delivered "files".
downloadSingleFile(Submission $sub, string $title)
static deleteUser(int $a_exc_id, int $a_user_id)
Deletes already delivered files.
ilExcAssMemberState $state
ILIAS Exercise InternalDomainService $domain
static lookupExerciseIdForReturnedId(int $a_returned_id)
Get exercise from submission id (used in ilObjMediaObject)
ilExPeerReview $peer_review
__construct(ilExAssignment $a_ass, int $a_user_id, ?ilExAssignmentTeam $a_team=null, bool $a_is_tutor=false, bool $a_public_submissions=false)
ilGlobalTemplateInterface $main_tpl
getSubmittedEntry(bool $print=false)
addResourceObject(string $a_wsp_id, ?string $a_text=null)
Add personal resource or repository object (ref_id) to assigment.
ilExAssignmentTeam $team
ilExAssignment $assignment
getLastOpeningHTMLView()
TODO -> get rid of getTableUserWhere and move to repository class Get a mysql timestamp from the last...
static getAssignmentParticipants(int $a_exercise_id, int $a_ass_id)
ILIAS Exercise Submission SubmissionManager $sub_manager
static findUserFiles(int $a_user_id, string $a_filetitle)
Check if given file was assigned Used in Blog/Portfolio.
static processZipFile(string $a_directory, string $a_file, bool $structure)
ilExAssignmentTypeInterface $ass_type
lookupNewFiles(?int $a_tutor=null)
Check how much files have been uploaded by the learner after the last download of the tutor.
isInTeam(?int $a_user_id=null)
updateTextSubmission(string $a_text)
Handle text assignment submissions.
getFeedbackId()
used for the legacy storage path of feedbacks only
static getDirectoryNameFromUserData(int $a_user_id)
getLastSubmission()
TODO -> get rid of getTableUserWhere and move to repository class Get the date of the last submission...
static getSubmissionsForFilename(string $a_filename, array $a_assignment_types=array())
Get assignment return entries for a filename.
ilExAssignmentTypes $ass_types
getLastDownloadTime(array $a_user_ids)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByIds(int $a_ass_id, int $a_user_id=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static utf8_encode(string $string)
static getASCIIFilename(string $a_filename)
static recursive_dirscan(string $dir, array &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
language handling
User class.
static _lookupName(int $a_user_id)
static _lookupType(int $id, bool $reference=false)
static _lookupTitle(int $obj_id)
static now()
Return current timestamp in Y-m-d H:i:s format.
static virusHandling(string $a_file, string $a_orig_name='', bool $a_clean=true)
$valid
Interface ilDBInterface.
quote($value, string $type)
manipulateF(string $query, array $types, array $values)
query(string $query)
Run a (read-only) Query on the database.
fetchAssoc(ilDBStatement $statement)
in(string $field, array $values, bool $negate=false, string $type="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$res
Definition: ltiservices.php:69
global $lng
Definition: privfeed.php:31
global $DIC
Definition: shib_login.php:26
$q
Definition: shib_logout.php:23