ILIAS  release_8 Revision v8.24
class.ilExSubmission.php
Go to the documentation of this file.
1<?php
2
27{
28 public const TYPE_FILE = "File";
29 public const TYPE_OBJECT = "Object"; // Blogs in WSP/Portfolio
30 public const TYPE_TEXT = "Text";
31 public const TYPE_REPO_OBJECT = "RepoObject"; // Wikis
32
33 protected ilObjUser $user;
34 protected ilDBInterface $db;
35 protected ilLanguage $lng;
36 protected ilCtrl $ctrl;
38 protected int $user_id;
39 protected ?ilExAssignmentTeam $team = null;
40 protected ?ilExPeerReview $peer_review = null;
41 protected bool $is_tutor;
42 protected bool $public_submissions;
46 private \ilGlobalTemplateInterface $main_tpl;
47
48 public function __construct(
49 ilExAssignment $a_ass,
50 int $a_user_id,
51 ilExAssignmentTeam $a_team = null,
52 bool $a_is_tutor = false,
53 bool $a_public_submissions = false
54 ) {
55 global $DIC;
56 $this->main_tpl = $DIC->ui()->mainTemplate();
57
58 $this->user = $DIC->user();
59 $this->db = $DIC->database();
60 $this->lng = $DIC->language();
61 $this->ctrl = $DIC->ctrl();
62
63 $this->assignment = $a_ass;
64 $this->ass_type = $this->assignment->getAssignmentType();
65 $this->ass_types = ilExAssignmentTypes::getInstance();
66
67 $this->user_id = $a_user_id;
68 $this->is_tutor = $a_is_tutor;
69 $this->public_submissions = $a_public_submissions;
70
71 $this->state = ilExcAssMemberState::getInstanceByIds($a_ass->getId(), $a_user_id);
72
73 if ($a_ass->hasTeam()) {
74 if (!$a_team) {
75 $this->team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $this->user_id);
76 } else {
77 $this->team = $a_team;
78 }
79 }
80
81 if ($this->assignment->getPeerReview()) {
82 $this->peer_review = new ilExPeerReview($this->assignment);
83 }
84 }
85
86 public function getSubmissionType(): string
87 {
88 return $this->assignment->getAssignmentType()->getSubmissionType();
89 }
90
91 public function getAssignment(): ilExAssignment
92 {
93 return $this->assignment;
94 }
95
96 public function getTeam(): ?ilExAssignmentTeam
97 {
98 return $this->team;
99 }
100
101 public function getPeerReview(): ?ilExPeerReview
102 {
103 return $this->peer_review;
104 }
105
106 public function validatePeerReviews(): array
107 {
108 $res = array();
109 foreach ($this->getUserIds() as $user_id) {
110 $valid = true;
111
112 // no peer review == valid
113 if ($this->peer_review) {
114 $valid = $this->peer_review->isFeedbackValidForPassed($user_id);
115 }
116
118 }
119 return $res;
120 }
121
122 public function getUserId(): int
123 {
124 return $this->user_id;
125 }
126
127 public function getUserIds(): array
128 {
129 if ($this->team &&
130 !$this->hasNoTeamYet()) {
131 return $this->team->getMembers();
132 }
133
134 // if has no team currently there still might be uploads attached
135 return array($this->user_id);
136 }
137
138 public function getFeedbackId(): string
139 {
140 if ($this->team) {
141 return "t" . $this->team->getId();
142 } else {
143 return (string) $this->getUserId();
144 }
145 }
146
147 public function hasSubmitted(): bool
148 {
149 return (bool) count($this->getFiles(null, true));
150 }
151
152 public function hasSubmittedPrintVersion(): bool
153 {
154 return $this->getSubmittedPrintFile() !== "";
155 }
156
157 public function getSubmittedPrintFile(): string
158 {
159 $submitted = $this->getFiles(
160 null,
161 false,
162 null,
163 true
164 );
165
166 if (count($submitted) > 0) {
167 $submitted = array_pop($submitted);
168
169 if (is_file($submitted['filename'])) {
170 return $submitted['filename'];
171 }
172 }
173
174 return "";
175 }
176
177 public function getSelectedObject(): ?array
178 {
179 $files = $this->getFiles();
180 if ($files !== []) {
181 return array_pop($files);
182 }
183 return null;
184 }
185
186 public function canSubmit(): bool
187 {
188 return ($this->isOwner() &&
189 $this->state->isSubmissionAllowed());
190 }
191
192 public function canView(): bool
193 {
195
196 if ($this->canSubmit() ||
197 $this->isTutor() ||
198 $this->isInTeam() ||
199 $this->public_submissions) {
200 return true;
201 }
202
203 // #16115
204 if ($this->peer_review) {
205 // peer review givers may view peer submissions
206 foreach ($this->peer_review->getPeerReviewsByPeerId($this->getUserId()) as $giver) {
207 if ($giver["giver_id"] == $ilUser->getId()) {
208 return true;
209 }
210 }
211 }
212
213 return false;
214 }
215
216 public function isTutor(): bool
217 {
218 return $this->is_tutor;
219 }
220
221 public function hasNoTeamYet(): bool
222 {
223 if ($this->assignment->hasTeam() &&
224 !$this->team->getId()) {
225 return true;
226 }
227 return false;
228 }
229
230 public function isInTeam(int $a_user_id = null): bool
231 {
233
234 if (!$a_user_id) {
235 $a_user_id = $ilUser->getId();
236 }
237 return in_array($a_user_id, $this->getUserIds());
238 }
239
240 public function isOwner(): bool
241 {
243
244 return ($ilUser->getId() == $this->getUserId());
245 }
246
247 public function hasPeerReviewAccess(): bool
248 {
249 return ($this->peer_review &&
250 $this->peer_review->hasPeerReviewAccess($this->user_id));
251 }
252
253 public function canAddFile(): bool
254 {
255 if (!$this->canSubmit()) {
256 return false;
257 }
258
259 $max = $this->getAssignment()->getMaxFile();
260 if ($max &&
261 $max <= sizeof($this->getFiles())) {
262 return false;
263 }
264
265 return true;
266 }
267
268
269 //
270 // FILES
271 //
272
273 protected function isLate(): bool
274 {
275 $dl = $this->state->getOfficialDeadline();
276 //$dl = $this->assignment->getPersonalDeadline($this->getUserId());
277 return ($dl && $dl < time());
278 }
279
280 protected function initStorage(): ilFSStorageExercise
281 {
282 return new ilFSStorageExercise($this->assignment->getExerciseId(), $this->assignment->getId());
283 }
284
285 protected function getStorageId(): int
286 {
287 if ($this->ass_type->isSubmissionAssignedToTeam()) {
288 $storage_id = $this->getTeam()->getId();
289 } else {
290 $storage_id = $this->getUserId();
291 }
292 return $storage_id;
293 }
294
295
300 public function uploadFile(
301 array $a_http_post_files,
302 bool $unzip = false
303 ): bool {
304 $ilDB = $this->db;
305
306 if (!$this->canAddFile()) {
307 return false;
308 }
309
310 if ($this->ass_type->isSubmissionAssignedToTeam()) {
311 $team_id = $this->getTeam()->getId();
312 $user_id = 0;
313 if ($team_id == 0) {
314 return false;
315 }
316 } else {
317 $team_id = 0;
318 $user_id = $this->getUserId();
319 }
320 $storage_id = $this->getStorageId();
321
322 $deliver_result = $this->initStorage()->uploadFile($a_http_post_files, $storage_id, $unzip);
323
324 if ($deliver_result) {
325 $next_id = $ilDB->nextId("exc_returned");
326 $query = sprintf(
327 "INSERT INTO exc_returned " .
328 "(returned_id, obj_id, user_id, filename, filetitle, mimetype, ts, ass_id, late, team_id) " .
329 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
330 $ilDB->quote($next_id, "integer"),
331 $ilDB->quote($this->assignment->getExerciseId(), "integer"),
332 $ilDB->quote($user_id, "integer"),
333 $ilDB->quote($deliver_result["fullname"], "text"),
334 $ilDB->quote(ilFileUtils::getValidFilename($a_http_post_files["name"]), "text"),
335 $ilDB->quote($deliver_result["mimetype"], "text"),
336 $ilDB->quote(ilUtil::now(), "timestamp"),
337 $ilDB->quote($this->assignment->getId(), "integer"),
338 $ilDB->quote($this->isLate(), "integer"),
339 $ilDB->quote($team_id, "integer")
340 );
341 $ilDB->manipulate($query);
342
343 if ($this->team) {
344 $this->team->writeLog(
346 $a_http_post_files["name"]
347 );
348 }
349
350 return true;
351 }
352 return false;
353 }
354
359 public function processUploadedZipFile(
360 string $fileTmp
361 ): bool {
362 $lng = $this->lng;
363
364 // Create unzip-directory
365 $newDir = ilFileUtils::ilTempnam();
366 ilFileUtils::makeDir($newDir);
367
368 $success = true;
369
370 try {
371 $filearray = [];
372 ilFileUtils::processZipFile($newDir, $fileTmp, false);
373 ilFileUtils::recursive_dirscan($newDir, $filearray);
374
375 // #18441 - check number of files in zip
376 $max_num = $this->assignment->getMaxFile();
377 if ($max_num) {
378 $current_num = count($this->getFiles());
379 $zip_num = count($filearray["file"]);
380 if ($current_num + $zip_num > $max_num) {
381 $success = false;
382 $this->main_tpl->setOnScreenMessage('failure', $lng->txt("exc_upload_error") . " [Zip1]", true);
383 }
384 }
385
386 if ($success) {
387 foreach ($filearray["file"] as $key => $filename) {
388 $a_http_post_files["name"] = ilFileUtils::utf8_encode($filename);
389 $a_http_post_files["type"] = "other";
390 $a_http_post_files["tmp_name"] = $filearray["path"][$key] . "/" . $filename;
391 $a_http_post_files["error"] = 0;
392 $a_http_post_files["size"] = filesize($filearray["path"][$key] . "/" . $filename);
393
394 if (!$this->uploadFile($a_http_post_files, true)) {
395 $success = false;
396 $this->main_tpl->setOnScreenMessage('failure', $lng->txt("exc_upload_error") . " [Zip2]", true);
397 }
398 }
399 }
400 } catch (ilFileUtilsException $e) {
401 $success = false;
402 $this->main_tpl->setOnScreenMessage('failure', $e->getMessage());
403 }
404
405 ilFileUtils::delDir($newDir);
406 return $success;
407 }
408
412 public static function getAllAssignmentFiles(
413 int $a_exc_id,
414 int $a_ass_id
415 ): array {
416 global $DIC;
417
418 $ilDB = $DIC->database();
419
420 $storage = new ilFSStorageExercise($a_exc_id, $a_ass_id);
421 $path = $storage->getAbsoluteSubmissionPath();
422
423 $ass_type = ilExAssignmentTypes::getInstance()->getById(ilExAssignment::lookupType($a_ass_id));
424
425 $query = "SELECT * FROM exc_returned WHERE ass_id = " .
426 $ilDB->quote($a_ass_id, "integer");
427
428 $res = $ilDB->query($query);
429 $delivered = [];
430 while ($row = $ilDB->fetchAssoc($res)) {
431 if ($ass_type->isSubmissionAssignedToTeam()) {
432 $storage_id = $row["team_id"];
433 } else {
434 $storage_id = $row["user_id"];
435 }
436
437 $row["timestamp"] = $row["ts"];
438 $row["filename"] = $path . "/" . $storage_id . "/" . basename($row["filename"]);
439 $delivered[] = $row;
440 }
441
442 return $delivered;
443 }
444
448 public static function getAssignmentFilesByUsers(
449 int $a_exc_id,
450 int $a_ass_id,
451 array $a_users
452 ): array {
453 global $DIC;
454
455 $ilDB = $DIC->database();
456
457 $storage = new ilFSStorageExercise($a_exc_id, $a_ass_id);
458 $path = $storage->getAbsoluteSubmissionPath();
459
460 $ass_type = ilExAssignmentTypes::getInstance()->getById(ilExAssignment::lookupType($a_ass_id));
461
462 $query = "SELECT * FROM exc_returned WHERE ass_id = " .
463 $ilDB->quote($a_ass_id, "integer") .
464 " AND user_id IN (" . implode(',', $a_users) . ")";
465
466 $res = $ilDB->query($query);
467 $delivered = [];
468 while ($row = $ilDB->fetchAssoc($res)) {
469 if ($ass_type->isSubmissionAssignedToTeam()) {
470 $storage_id = $row["team_id"];
471 } else {
472 $storage_id = $row["user_id"];
473 }
474
475 $row["timestamp"] = $row["ts"];
476 $row["filename"] = $path . "/" . $storage_id . "/" . basename($row["filename"]);
477 $delivered[] = $row;
478 }
479
480 return $delivered;
481 }
482
487 public function getFiles(
488 array $a_file_ids = null,
489 bool $a_only_valid = false,
490 string $a_min_timestamp = null,
491 bool $print_versions = false
492 ): array {
493 $ilDB = $this->db;
494
495 $sql = "SELECT * FROM exc_returned" .
496 " WHERE ass_id = " . $ilDB->quote($this->getAssignment()->getId(), "integer");
497
498 $sql .= " AND " . $this->getTableUserWhere(true);
499
500
501 if ($a_file_ids) {
502 $sql .= " AND " . $ilDB->in("returned_id", $a_file_ids, false, "integer");
503 }
504
505 if ($a_min_timestamp) {
506 $sql .= " AND ts > " . $ilDB->quote($a_min_timestamp, "timestamp");
507 }
508
509 $result = $ilDB->query($sql);
510
511 $delivered_files = array();
512 if ($ilDB->numRows($result)) {
513 $path = $this->initStorage()->getAbsoluteSubmissionPath();
514
515 while ($row = $ilDB->fetchAssoc($result)) {
516 // blog/portfolio/text submissions
517 if ($a_only_valid &&
518 !$row["filename"] &&
519 !(trim($row["atext"]))) {
520 continue;
521 }
522
523 $row["owner_id"] = $row["user_id"];
524 $row["timestamp"] = $row["ts"];
525 $row["timestamp14"] = substr($row["ts"], 0, 4) .
526 substr($row["ts"], 5, 2) . substr($row["ts"], 8, 2) .
527 substr($row["ts"], 11, 2) . substr($row["ts"], 14, 2) .
528 substr($row["ts"], 17, 2);
529
530 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
531 $storage_id = $row["team_id"];
532 } else {
533 $storage_id = $row["user_id"];
534 }
535
536
537 $row["filename"] = $path .
538 "/" . $storage_id . "/" . basename($row["filename"]);
539
540 // see 22301, 22719
541 if (is_file($row["filename"]) || (!$this->assignment->getAssignmentType()->usesFileUpload())) {
542 $delivered_files[] = $row;
543 }
544 }
545 }
546
547 // filter print versions
548 if (in_array($this->assignment->getType(), [
552 ])) {
553 $delivered_files = array_filter($delivered_files, function ($i) use ($print_versions) {
554 $is_print_version = false;
555 if (substr($i["filetitle"], strlen($i["filetitle"]) - 5) == "print") {
556 $is_print_version = true;
557 }
558 if (substr($i["filetitle"], strlen($i["filetitle"]) - 9) == "print.zip") {
559 $is_print_version = true;
560 }
561 return ($is_print_version == $print_versions);
562 });
563 }
564
565 return $delivered_files;
566 }
567
572 public function lookupNewFiles(
573 int $a_tutor = null
574 ): array {
575 $ilDB = $this->db;
576 $ilUser = $this->user;
577
578 $tutor = ($a_tutor)
579 ?: $ilUser->getId();
580
581 $where = " AND " . $this->getTableUserWhere(true);
582
583 $q = "SELECT exc_returned.returned_id AS id " .
584 "FROM exc_usr_tutor, exc_returned " .
585 "WHERE exc_returned.ass_id = exc_usr_tutor.ass_id " .
586 " AND exc_returned.user_id = exc_usr_tutor.usr_id " .
587 " AND exc_returned.ass_id = " . $ilDB->quote($this->getAssignment()->getId(), "integer") .
588 $where .
589 " AND exc_usr_tutor.tutor_id = " . $ilDB->quote($tutor, "integer") .
590 " AND exc_usr_tutor.download_time < exc_returned.ts ";
591
592 $new_up_set = $ilDB->query($q);
593
594 $new_up = array();
595 while ($new_up_rec = $ilDB->fetchAssoc($new_up_set)) {
596 $new_up[] = $new_up_rec["id"];
597 }
598
599 return $new_up;
600 }
601
605 public static function lookupExerciseIdForReturnedId(
606 int $a_returned_id
607 ): int {
608 global $DIC;
609
610 $ilDB = $DIC->database();
611
612 $set = $ilDB->query("SELECT obj_id" .
613 " FROM exc_returned" .
614 " WHERE returned_id = " . $ilDB->quote($a_returned_id, "integer"));
615 $row = $ilDB->fetchAssoc($set);
616 return (int) $row["obj_id"];
617 }
618
623 public static function findUserFiles(
624 int $a_user_id,
625 string $a_filetitle
626 ): array {
627 global $DIC;
628
629 $ilDB = $DIC->database();
630
631 $set = $ilDB->query("SELECT obj_id, ass_id" .
632 " FROM exc_returned" .
633 " WHERE user_id = " . $ilDB->quote($a_user_id, "integer") .
634 " AND filetitle = " . $ilDB->quote($a_filetitle, "text"));
635 $res = array();
636 while ($row = $ilDB->fetchAssoc($set)) {
637 $res[$row["ass_id"]] = $row;
638 }
639 return $res;
640 }
641
642 public function deleteAllFiles(): void
643 {
644 $files = array();
645 // normal files
646 foreach ($this->getFiles() as $item) {
647 $files[] = $item["returned_id"];
648 }
649 // print versions
650 foreach ($this->getFiles(null, false, null, true) as $item) {
651 $files[] = $item["returned_id"];
652 }
653 if ($files !== []) {
654 $this->deleteSelectedFiles($files);
655 }
656 }
657
662 public function deleteSelectedFiles(
663 array $file_id_array
664 ): void {
665 $ilDB = $this->db;
666
667
668 $where = " AND " . $this->getTableUserWhere(true);
669
670
671 if ($file_id_array === []) {
672 return;
673 }
674
675 if ($file_id_array !== []) {
676 $result = $ilDB->query("SELECT * FROM exc_returned" .
677 " WHERE " . $ilDB->in("returned_id", $file_id_array, false, "integer") .
678 $where);
679
680 if ($ilDB->numRows($result)) {
681 $result_array = array();
682 while ($row = $ilDB->fetchAssoc($result)) {
683 $row["timestamp"] = $row["ts"];
684 $result_array[] = $row;
685 }
686
687 // delete the entries in the database
688 $ilDB->manipulate("DELETE FROM exc_returned" .
689 " WHERE " . $ilDB->in("returned_id", $file_id_array, false, "integer") .
690 $where);
691
692 // delete the files
693 $path = $this->initStorage()->getAbsoluteSubmissionPath();
694 foreach ($result_array as $value) {
695 if ($value["filename"]) {
696 if ($this->team) {
697 $this->team->writeLog(
699 $value["filetitle"]
700 );
701 }
702
703 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
704 $storage_id = $value["team_id"];
705 } else {
706 $storage_id = $value["user_id"];
707 }
708
709 $filename = $path . "/" . $storage_id . "/" . basename($value["filename"]);
710 if (file_exists($filename)) {
711 unlink($filename);
712 }
713 }
714 }
715 }
716 }
717 }
718
723 public static function deleteUser(
724 int $a_exc_id,
725 int $a_user_id
726 ): void {
727 foreach (ilExAssignment::getInstancesByExercise($a_exc_id) as $ass) {
728 $submission = new self($ass, $a_user_id);
729 $submission->deleteAllFiles();
730
731 // remove from any team
732 $team = $submission->getTeam();
733 if ($team) {
734 $team->removeTeamMember($a_user_id);
735 }
736
737 // #14900
738 $member_status = $ass->getMemberStatus($a_user_id);
739 $member_status->setStatus("notgraded");
740 $member_status->update();
741 }
742 }
743
748 protected function getLastDownloadTime(
749 array $a_user_ids
750 ): string {
751 $ilDB = $this->db;
752 $ilUser = $this->user;
753
754 $q = "SELECT download_time FROM exc_usr_tutor WHERE " .
755 " ass_id = " . $ilDB->quote($this->getAssignment()->getId(), "integer") . " AND " .
756 $ilDB->in("usr_id", $a_user_ids, "", "integer") . " AND " .
757 " tutor_id = " . $ilDB->quote($ilUser->getId(), "integer") .
758 " ORDER BY download_time DESC";
759 $lu_set = $ilDB->query($q);
760 $lu_rec = $ilDB->fetchAssoc($lu_set);
761 return $lu_rec["download_time"] ?? "";
762 }
763
764 public function downloadFiles(
765 array $a_file_ids = null,
766 bool $a_only_new = false,
767 bool $a_peer_review_mask_filename = false
768 ): bool {
769 $ilUser = $this->user;
771
772 $user_ids = $this->getUserIds();
773 $is_team = $this->assignment->hasTeam();
774 // get last download time
775 $download_time = null;
776 if ($a_only_new) {
777 $download_time = $this->getLastDownloadTime($user_ids);
778 }
779
780 if ($this->is_tutor) {
781 $this->updateTutorDownloadTime();
782 }
783
784 if ($a_peer_review_mask_filename) {
785 // process peer review sequence id
786 $peer_id = null;
787 foreach ($this->peer_review->getPeerReviewsByGiver($ilUser->getId()) as $idx => $item) {
788 if ($item["peer_id"] == $this->getUserId()) {
789 $peer_id = $idx + 1;
790 break;
791 }
792 }
793 // this will remove personal info from zip-filename
794 $is_team = true;
795 }
796
797 $files = $this->getFiles($a_file_ids, false, $download_time);
798
799 if ($files !== []) {
800 if (count($files) == 1) {
801 $file = array_pop($files);
802
803 switch ($this->assignment->getType()) {
806 $file["filetitle"] = ilObjUser::_lookupName($file["user_id"]);
807 $file["filetitle"] = ilObject::_lookupTitle($this->assignment->getExerciseId()) . " - " .
808 $this->assignment->getTitle() . " - " .
809 $file["filetitle"]["firstname"] . " " .
810 $file["filetitle"]["lastname"] . " (" .
811 $file["filetitle"]["login"] . ").zip";
812 break;
813
814 // @todo: generalize
816 $file["filetitle"] = ilObject::_lookupTitle($this->assignment->getExerciseId()) . " - " .
817 $this->assignment->getTitle() . " (Team " . $this->getTeam()->getId() . ").zip";
818 break;
819
820 default:
821 break;
822 }
823
824 if ($a_peer_review_mask_filename) {
825 $title_a = explode(".", $file["filetitle"]);
826 $suffix = array_pop($title_a);
827 $file["filetitle"] = $this->assignment->getTitle() . "_peer" . $peer_id . "." . $suffix;
828 } elseif ($file["late"]) {
829 $file["filetitle"] = $lng->txt("exc_late_submission") . " - " .
830 $file["filetitle"];
831 }
832
833 $this->downloadSingleFile($file["user_id"], $file["filename"], $file["filetitle"], $file["team_id"]);
834 } else {
835 $array_files = array();
836 foreach ($files as $seq => $file) {
837 if ($this->assignment->getAssignmentType()->isSubmissionAssignedToTeam()) {
838 $storage_id = $file["team_id"];
839 } else {
840 $storage_id = $file["user_id"];
841 }
842
843 $src = basename($file["filename"]);
844 if ($a_peer_review_mask_filename) {
845 $src_a = explode(".", $src);
846 $suffix = array_pop($src_a);
847 $tgt = $this->assignment->getTitle() . "_peer" . $peer_id .
848 "_" . (++$seq) . "." . $suffix;
849
850 $array_files[$storage_id][] = array(
851 "src" => $src,
852 "tgt" => $tgt
853 );
854 } else {
855 $array_files[$storage_id][] = array(
856 "src" => $src,
857 "late" => $file["late"]
858 );
859 }
860 }
861 $this->downloadMultipleFiles(
862 $array_files,
863 ($is_team ? null : $this->getUserId()),
864 $is_team
865 );
866 }
867 } else {
868 return false;
869 }
870
871 return true;
872 }
873
874 // Update the timestamp of the last download of current user (=tutor)
875 public function updateTutorDownloadTime(): void
876 {
877 $ilUser = $this->user;
878 $ilDB = $this->db;
879
880 $exc_id = $this->assignment->getExerciseId();
881 $ass_id = $this->assignment->getId();
882
883 foreach ($this->getUserIds() as $user_id) {
884 $ilDB->manipulateF(
885 "DELETE FROM exc_usr_tutor " .
886 "WHERE ass_id = %s AND usr_id = %s AND tutor_id = %s",
887 array("integer", "integer", "integer"),
888 array($ass_id, $user_id, $ilUser->getId())
889 );
890
891 $ilDB->manipulateF(
892 "INSERT INTO exc_usr_tutor (ass_id, obj_id, usr_id, tutor_id, download_time) VALUES " .
893 "(%s, %s, %s, %s, %s)",
894 array("integer", "integer", "integer", "integer", "timestamp"),
895 array($ass_id, $exc_id, $user_id, $ilUser->getId(), ilUtil::now())
896 );
897 }
898 }
899
900 protected function downloadSingleFile(
901 int $a_user_id,
902 string $filename,
903 string $filetitle,
904 int $a_team_id = 0
905 ): void {
906 if ($this->ass_type->isSubmissionAssignedToTeam()) {
907 $storage_id = $a_team_id;
908 } else {
909 $storage_id = $a_user_id;
910 }
911
912 $filename = $this->initStorage()->getAbsoluteSubmissionPath() .
913 "/" . $storage_id . "/" . basename($filename);
914
916 }
917
918 protected function downloadMultipleFiles(
919 array $a_filenames,
920 ?int $a_user_id,
921 bool $a_multi_user = false
922 ): void {
923 $lng = $this->lng;
924 $a_user_id = (int) $a_user_id;
925
926 $path = $this->initStorage()->getAbsoluteSubmissionPath();
927
928 $cdir = getcwd();
929
930 $zip = PATH_TO_ZIP;
931 $tmpdir = ilFileUtils::ilTempnam();
932 $tmpfile = ilFileUtils::ilTempnam();
933 $tmpzipfile = $tmpfile . ".zip";
934
935 ilFileUtils::makeDir($tmpdir);
936 chdir($tmpdir);
937
938 $assTitle = ilExAssignment::lookupTitle($this->assignment->getId());
939 $deliverFilename = str_replace(" ", "_", $assTitle);
940 if ($a_user_id > 0 && !$a_multi_user) {
941 $userName = ilObjUser::_lookupName($a_user_id);
942 $deliverFilename .= "_" . $userName["lastname"] . "_" . $userName["firstname"];
943 } else {
944 $deliverFilename .= "_files";
945 }
946 $orgDeliverFilename = trim($deliverFilename);
947 $deliverFilename = ilFileUtils::getASCIIFilename($orgDeliverFilename);
948 ilFileUtils::makeDir($tmpdir . "/" . $deliverFilename);
949 chdir($tmpdir . "/" . $deliverFilename);
950
951 //copy all files to a temporary directory and remove them afterwards
952 $parsed_files = $duplicates = array();
953 foreach ($a_filenames as $storage_id => $files) {
954 $pathname = $path . "/" . $storage_id;
955
956 foreach ($files as $filename) {
957 // peer review masked filenames, see deliverReturnedFiles()
958 if (isset($filename["tgt"])) {
959 $newFilename = $filename["tgt"];
960 $filename = $filename["src"];
961 } else {
962 $late = $filename["late"];
963 $filename = $filename["src"];
964
965 // remove timestamp
966 $newFilename = trim($filename);
967 $pos = strpos($newFilename, "_");
968 if ($pos !== false) {
969 $newFilename = substr($newFilename, $pos + 1);
970 }
971 // #11070
972 $chkName = strtolower($newFilename);
973 if (array_key_exists($chkName, $duplicates)) {
974 $suffix = strrpos($newFilename, ".");
975 $newFilename = substr($newFilename, 0, $suffix) .
976 " (" . (++$duplicates[$chkName]) . ")" .
977 substr($newFilename, $suffix);
978 } else {
979 $duplicates[$chkName] = 1;
980 }
981
982 if ($late) {
983 $newFilename = $lng->txt("exc_late_submission") . " - " .
984 $newFilename;
985 }
986 }
987
988 $newFilename = ilFileUtils::getASCIIFilename($newFilename);
989 $newFilename = $tmpdir . DIRECTORY_SEPARATOR . $deliverFilename . DIRECTORY_SEPARATOR . $newFilename;
990 // copy to temporal directory
991 $oldFilename = $pathname . DIRECTORY_SEPARATOR . $filename;
992 if (!copy($oldFilename, $newFilename)) {
993 echo 'Could not copy ' . $oldFilename . ' to ' . $newFilename;
994 }
995 touch($newFilename, filectime($oldFilename));
996 $parsed_files[] = ilShellUtil::escapeShellArg(
997 $deliverFilename . DIRECTORY_SEPARATOR . basename($newFilename)
998 );
999 }
1000 }
1001
1002 chdir($tmpdir);
1003 $zipcmd = $zip . " " . ilShellUtil::escapeShellArg($tmpzipfile) . " " . implode(" ", $parsed_files);
1004
1005 exec($zipcmd);
1006 ilFileUtils::delDir($tmpdir);
1007
1008 chdir($cdir);
1009 ilFileDelivery::deliverFileLegacy($tmpzipfile, $orgDeliverFilename . ".zip", "", false, true);
1010 exit;
1011 }
1012
1017 public static function downloadAllAssignmentFiles(
1018 ilExAssignment $a_ass,
1019 array $members,
1020 string $to_path
1021 ): void {
1022 global $DIC;
1023
1024 $lng = $DIC->language();
1026
1027 $storage = new ilFSStorageExercise($a_ass->getExerciseId(), $a_ass->getId());
1028 $storage->create();
1029
1030 ksort($members);
1031 //$savepath = $this->getExercisePath() . "/" . $this->obj_id . "/";
1032 $savepath = $storage->getAbsoluteSubmissionPath();
1033 $cdir = getcwd();
1034
1035
1036 // important check: if the directory does not exist
1037 // ILIAS stays in the current directory (echoing only a warning)
1038 // and the zip command below archives the whole ILIAS directory
1039 // (including the data directory) and sends a mega file to the user :-o
1040 if (!is_dir($savepath)) {
1041 return;
1042 }
1043 // Safe mode fix
1044 // chdir($this->getExercisePath());
1045
1046 $tmpdir = $storage->getTempPath();
1047 chdir($tmpdir);
1048 $zip = PATH_TO_ZIP;
1049
1050 // check free diskspace
1051 $dirsize = 0;
1052 foreach (array_keys($members) as $id) {
1053 $directory = $savepath . DIRECTORY_SEPARATOR . $id;
1054 $dirsize += ilFileUtils::dirsize($directory);
1055 }
1056 if ($dirsize > disk_free_space($tmpdir)) {
1057 return;
1058 }
1059
1060 $ass_type = $a_ass->getType();
1061
1062 // copy all member directories to the temporary folder
1063 // switch from id to member name and append the login if the member name is double
1064 // ensure that no illegal filenames will be created
1065 // remove timestamp from filename
1066 $team_map = null;
1067 $team_dirs = null;
1068 if ($a_ass->hasTeam()) {
1069 $team_dirs = array();
1070 $team_map = ilExAssignmentTeam::getAssignmentTeamMap($a_ass->getId());
1071 }
1072 foreach ($members as $id => $item) {
1073 $user_files = $item["files"] ?? null;
1074 $sourcedir = $savepath . DIRECTORY_SEPARATOR . $id;
1075 if (!is_dir($sourcedir)) {
1076 continue;
1077 }
1078
1079 // group by teams
1080 $team_dir = "";
1081 if (is_array($team_map) &&
1082 array_key_exists($id, $team_map)) {
1083 $team_id = $team_map[$id];
1084 if (!array_key_exists($team_id, $team_dirs)) {
1085 $team_dir = $lng->txt("exc_team") . " " . $team_id;
1086 ilFileUtils::makeDir($team_dir);
1087 $team_dirs[$team_id] = $team_dir;
1088 }
1089 $team_dir = $team_dirs[$team_id] . DIRECTORY_SEPARATOR;
1090 }
1091
1092 if ($a_ass->getAssignmentType()->isSubmissionAssignedToTeam()) {
1093 $targetdir = $team_dir . ilFileUtils::getASCIIFilename(
1094 $item["name"]
1095 );
1096 if ($targetdir == "") {
1097 continue;
1098 }
1099 } else {
1100 $targetdir = self::getDirectoryNameFromUserData($id);
1101 if ($a_ass->getAssignmentType()->usesTeams()) {
1102 $targetdir = $team_dir . $targetdir;
1103 }
1104 }
1105
1106 $log->debug("Creation target directory: " . $targetdir);
1107 ilFileUtils::makeDir($targetdir);
1108
1109 $log->debug("Scanning source directory: " . $sourcedir);
1110 $sourcefiles = scandir($sourcedir);
1111 $duplicates = array();
1112 foreach ($sourcefiles as $sourcefile) {
1113 if ($sourcefile == "." || $sourcefile == "..") {
1114 continue;
1115 }
1116
1117 $targetfile = trim(basename($sourcefile));
1118 $pos = strpos($targetfile, "_");
1119 if ($pos !== false) {
1120 $targetfile = substr($targetfile, $pos + 1);
1121 }
1122
1123 if ($a_ass->getAssignmentType()->getSubmissionType() == self::TYPE_REPO_OBJECT) {
1124 $obj_id = ilObject::_lookupObjId($targetfile);
1125 $obj_type = ilObject::_lookupType($obj_id);
1126 $targetfile = $obj_type . "_" . $obj_id . ".zip";
1127 }
1128
1129
1130 // #14536
1131 if (array_key_exists($targetfile, $duplicates)) {
1132 $suffix = strrpos($targetfile, ".");
1133 $targetfile = substr($targetfile, 0, $suffix) .
1134 " (" . (++$duplicates[$targetfile]) . ")" .
1135 substr($targetfile, $suffix);
1136 } else {
1137 $duplicates[$targetfile] = 1;
1138 }
1139
1140 // late submission?
1141 if (isset($user_files)) { // see #23900
1142 foreach ($user_files as $file) {
1143 if (basename($file["filename"]) == $sourcefile) {
1144 if ($file["late"]) {
1145 $targetfile = $lng->txt("exc_late_submission") . " - " .
1146 $targetfile;
1147 }
1148 break;
1149 }
1150 }
1151 }
1152
1153 $targetfile = ilFileUtils::getASCIIFilename($targetfile);
1154 $targetfile = $targetdir . DIRECTORY_SEPARATOR . $targetfile;
1155 $sourcefile = $sourcedir . DIRECTORY_SEPARATOR . $sourcefile;
1156
1157 $log->debug("Copying: " . $sourcefile . " -> " . $targetfile);
1158
1159 if (!copy($sourcefile, $targetfile)) {
1160 throw new ilExerciseException("Could not copy " . basename($sourcefile) . " to '" . $targetfile . "'.");
1161 } else {
1162 // preserve time stamp
1163 touch($targetfile, filectime($sourcefile));
1164
1165 // blogs and portfolios are stored as zip and have to be unzipped
1166 if ($ass_type == ilExAssignment::TYPE_PORTFOLIO ||
1167 $ass_type == ilExAssignment::TYPE_BLOG) {
1168 $log->debug("Unzipping: " . $targetfile);
1169 $log->debug("Current directory is: " . getcwd());
1170
1171 ilFileUtils::unzip($targetfile);
1172 unlink($targetfile);
1173 }
1174 }
1175 }
1176 }
1177 $tmpzipfile = ilFileUtils::getASCIIFilename($lng->txt("exc_ass_submission_zip")) . ".zip";
1178 // Safe mode fix
1179 $zipcmd = $zip . " -r " . ilShellUtil::escapeShellArg($tmpzipfile) . " .";
1180 exec($zipcmd);
1181 //$path_final_zip_file = $to_path.DIRECTORY_SEPARATOR."Submissions/".$tmpzipfile;
1182 $path_final_zip_file = $to_path . DIRECTORY_SEPARATOR . $tmpzipfile;
1183
1184 if (file_exists($tmpdir . DIRECTORY_SEPARATOR . $tmpzipfile)) {
1185 copy($tmpzipfile, $path_final_zip_file);
1186 ilFileUtils::delDir($tmpdir);
1187
1188 //unzip the submissions zip file.(decided to unzip to allow the excel link the files more obvious when blog/portfolio)
1189 chdir($to_path);
1190 //TODO Bug in ilUtil -> if flat unzip fails. We can get rid of creating Submissions directory
1191 //ilUtil::unzip($path_final_zip_file,FALSE, TRUE);
1192 ilFileUtils::unzip($path_final_zip_file);
1193 unlink($path_final_zip_file);
1194 }
1195
1196 chdir($cdir);
1197 }
1198
1199
1200 // Get user/team where clause
1201 public function getTableUserWhere(
1202 bool $a_team_mode = false
1203 ): string {
1204 $ilDB = $this->db;
1205
1206 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
1207 $team_id = $this->getTeam()->getId();
1208 $where = " team_id = " . $ilDB->quote($team_id, "integer") . " ";
1209 } else {
1210 if ($a_team_mode) {
1211 $where = " " . $ilDB->in("user_id", $this->getUserIds(), "", "integer") . " ";
1212 } else {
1213 $where = " user_id = " . $ilDB->quote($this->getUserId(), "integer");
1214 }
1215 }
1216 return $where;
1217 }
1218
1219
1224 public function getLastSubmission(): ?string
1225 {
1226 $ilDB = $this->db;
1227
1228 $ilDB->setLimit(1, 0);
1229
1230 $q = "SELECT obj_id,user_id,ts FROM exc_returned" .
1231 " WHERE ass_id = " . $ilDB->quote($this->assignment->getId(), "integer") .
1232 " AND " . $this->getTableUserWhere(true) .
1233 " AND (filename IS NOT NULL OR atext IS NOT NULL)" .
1234 " AND ts IS NOT NULL" .
1235 " ORDER BY ts DESC";
1236 $usr_set = $ilDB->query($q);
1237 $array = $ilDB->fetchAssoc($usr_set);
1238 return ($array["ts"] ?? null);
1239 }
1240
1245 public function getLastOpeningHTMLView(): ?string
1246 {
1247 $this->db->setLimit(1, 0);
1248
1249 $q = "SELECT web_dir_access_time FROM exc_returned" .
1250 " WHERE ass_id = " . $this->db->quote($this->assignment->getId(), "integer") .
1251 " AND (filename IS NOT NULL OR atext IS NOT NULL)" .
1252 " AND web_dir_access_time IS NOT NULL" .
1253 " AND " . $this->getTableUserWhere(true) .
1254 " ORDER BY web_dir_access_time DESC";
1255
1256 $res = $this->db->query($q);
1257
1258 $data = $this->db->fetchAssoc($res);
1259
1260 return $data["web_dir_access_time"] ?? null;
1261 }
1262
1263
1264 //
1265 // OBJECTS
1266 //
1267
1273 public function addResourceObject(
1274 string $a_wsp_id, // note: text assignments currently call this with "TEXT"
1275 string $a_text = null
1276 ): int {
1277 $ilDB = $this->db;
1278
1279 if ($this->getAssignment()->getAssignmentType()->isSubmissionAssignedToTeam()) {
1280 $user_id = 0;
1281 $team_id = $this->getTeam()->getId();
1282 } else {
1283 $user_id = $this->getUserId();
1284 $team_id = 0;
1285 }
1286
1287 // repository objects must be unique in submissions
1288 // the same repo object cannot be used in different submissions or even different assignment/exercises
1289 // why? -> the access handling would fail, since the access depends e.g. on teams or even phase of the
1290 // assignment
1291 if ($this->getAssignment()->getAssignmentType()->getSubmissionType() == ilExSubmission::TYPE_REPO_OBJECT) {
1292 $repos_ass_type_ids = $this->ass_types->getIdsForSubmissionType(ilExSubmission::TYPE_REPO_OBJECT);
1293 $subs = $this->getSubmissionsForFilename($a_wsp_id, $repos_ass_type_ids);
1294 if ($subs !== []) {
1295 throw new ilExerciseException("Repository object $a_wsp_id is already assigned to another assignment.");
1296 }
1297 }
1298
1299 $next_id = $ilDB->nextId("exc_returned");
1300 $query = sprintf(
1301 "INSERT INTO exc_returned " .
1302 "(returned_id, obj_id, user_id, filetitle, ass_id, ts, atext, late, team_id) " .
1303 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)",
1304 $ilDB->quote($next_id, "integer"),
1305 $ilDB->quote($this->assignment->getExerciseId(), "integer"),
1306 $ilDB->quote($user_id, "integer"),
1307 $ilDB->quote($a_wsp_id, "text"),
1308 $ilDB->quote($this->assignment->getId(), "integer"),
1309 $ilDB->quote(ilUtil::now(), "timestamp"),
1310 $ilDB->quote($a_text, "text"),
1311 $ilDB->quote($this->isLate(), "integer"),
1312 $ilDB->quote($team_id, "integer")
1313 );
1314 $ilDB->manipulate($query);
1315
1316 return $next_id;
1317 }
1318
1319 /*
1320 * Remove ressource from assignement (and delete
1321 * its submission): Note: The object itself will not be deleted.
1322 */
1323 public function deleteResourceObject(): void
1324 {
1325 $this->deleteAllFiles();
1326 }
1327
1333 public function updateTextSubmission(string $a_text): ?int
1334 {
1335 $ilDB = $this->db;
1336
1337 $files = $this->getFiles();
1338
1339 // no text = remove submission
1340 if (!trim($a_text)) {
1341 $this->deleteAllFiles();
1342 return null;
1343 }
1344
1345 if (!$files) {
1346 return $this->addResourceObject("TEXT", $a_text);
1347 } else {
1348 $files = array_shift($files);
1349 $id = $files["returned_id"];
1350 if ($id) {
1351 $ilDB->manipulate("UPDATE exc_returned" .
1352 " SET atext = " . $ilDB->quote($a_text, "text") .
1353 ", ts = " . $ilDB->quote(ilUtil::now(), "timestamp") .
1354 ", late = " . $ilDB->quote($this->isLate(), "integer") .
1355 " WHERE returned_id = " . $ilDB->quote($id, "integer"));
1356 return $id;
1357 }
1358 }
1359 return null;
1360 }
1361
1362 //
1363 // GUI helper
1364 //
1365
1369 public function getDownloadedFilesInfoForTableGUIS(): array
1370 {
1371 $lng = $this->lng;
1372 $ilCtrl = $this->ctrl;
1373
1374 $result = array();
1375 $result["files"]["count"] = "---";
1376
1377 // submission:
1378 // see if files have been resubmmited after solved
1379 $last_sub = $this->getLastSubmission();
1380 if ($last_sub) {
1381 $last_sub = ilDatePresentation::formatDate(new ilDateTime($last_sub, IL_CAL_DATETIME));
1382 } else {
1383 $last_sub = "---";
1384 }
1385 $result["last_submission"]["txt"] = $lng->txt("exc_last_submission");
1386 $result["last_submission"]["value"] = $last_sub;
1387
1388 // #16994
1389 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", $this->getUserId());
1390
1391 // assignment type specific
1392 switch ($this->assignment->getType()) {
1394 // data is merged by team - see above
1395 // fallthrough
1396
1398 $all_files = $this->getFiles();
1399 $late_files = 0;
1400 foreach ($all_files as $file) {
1401 if ($file["late"]) {
1402 $late_files++;
1403 }
1404 }
1405
1406 // nr of submitted files
1407 $result["files"]["txt"] = $lng->txt("exc_files_returned");
1408 if ($late_files !== 0) {
1409 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . " (" . $late_files . ")</span>";
1410 }
1411 $sub_cnt = count($all_files);
1412 $new = $this->lookupNewFiles();
1413 if ($new !== []) {
1414 $sub_cnt .= " " . sprintf($lng->txt("cnt_new"), count($new));
1415 }
1416
1417 $result["files"]["count"] = $sub_cnt;
1418
1419 // download command
1420 if ($sub_cnt > 0) {
1421 $result["files"]["download_url"] =
1422 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1423
1424 if (count($new) <= 0) {
1425 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1426 } else {
1427 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_all_files");
1428 }
1429
1430 // download new files only
1431 if ($new !== []) {
1432 $result["files"]["download_new_url"] =
1433 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadNewReturned");
1434
1435 $result["files"]["download_new_txt"] = $lng->txt("exc_tbl_action_download_new_files");
1436 }
1437 }
1438 break;
1439
1441 $result["files"]["txt"] = $lng->txt("exc_blog_returned");
1442 $blogs = $this->getFiles();
1443 if ($blogs !== []) {
1444 $blogs = array_pop($blogs);
1445 if ($blogs && substr($blogs["filename"], -1) != "/") {
1446 if ($blogs["late"]) {
1447 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
1448 }
1449
1450 $result["files"]["count"] = 1;
1451
1452 $result["files"]["download_url"] =
1453 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1454
1455 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1456 }
1457 }
1458 break;
1459
1461 $result["files"]["txt"] = $lng->txt("exc_portfolio_returned");
1462 $portfolios = $this->getFiles();
1463 if ($portfolios !== []) {
1464 $portfolios = array_pop($portfolios);
1465 if ($portfolios && substr($portfolios["filename"], -1) != "/") {
1466 if ($portfolios["late"]) {
1467 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
1468 }
1469
1470 $result["files"]["count"] = 1;
1471
1472 $result["files"]["download_url"] =
1473 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1474
1475 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1476 }
1477 }
1478 break;
1479
1481 $result["files"]["txt"] = $lng->txt("exc_files_returned_text");
1482 $files = $this->getFiles();
1483 if ($files !== []) {
1484 $result["files"]["count"] = 1;
1485
1486 $files = array_shift($files);
1487 if (trim($files["atext"]) !== '' && trim($files["atext"]) !== '0') {
1488 if ($files["late"]) {
1489 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
1490 }
1491
1492 $result["files"]["download_url"] =
1493 $ilCtrl->getLinkTargetByClass("ilexsubmissiontextgui", "showAssignmentText");
1494
1495 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_text_assignment_show");
1496 }
1497 }
1498 break;
1499
1501 $result["files"]["txt"] = $lng->txt("exc_wiki_returned");
1502 $objs = $this->getFiles();
1503 if ($objs !== []) {
1504 $objs = array_pop($objs);
1505 if ($objs && substr($objs["filename"], -1) != "/") {
1506 if ($objs["late"]) {
1507 $result["files"]["txt"] .= ' - <span class="warning">' . $lng->txt("exc_late_submission") . "</span>";
1508 }
1509
1510 $result["files"]["count"] = 1;
1511
1512 $result["files"]["download_url"] =
1513 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1514
1515 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1516 }
1517 }
1518 break;
1519 }
1520
1521 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", "");
1522
1523 return $result;
1524 }
1525
1529 public static function getSubmissionsForFilename(
1530 string $a_filename,
1531 array $a_assignment_types = array()
1532 ): array {
1533 global $DIC;
1534
1535 $db = $DIC->database();
1536
1537 $query = "SELECT * FROM exc_returned r LEFT JOIN exc_assignment a" .
1538 " ON (r.ass_id = a.id) " .
1539 " WHERE r.filetitle = " . $db->quote($a_filename, "string");
1540
1541 if (is_array($a_assignment_types) && $a_assignment_types !== []) {
1542 $query .= " AND " . $db->in("a.type", $a_assignment_types, false, "integer");
1543 }
1544
1545 $set = $db->query($query);
1546 $rets = array();
1547 while ($rec = $db->fetchAssoc($set)) {
1548 $rets[] = $rec;
1549 }
1550
1551
1552 return $rets;
1553 }
1554
1555 public static function getDirectoryNameFromUserData(int $a_user_id): string
1556 {
1557 $userName = ilObjUser::_lookupName($a_user_id);
1559 trim($userName["lastname"]) . "_" .
1560 trim($userName["firstname"]) . "_" .
1561 trim($userName["login"]) . "_" .
1562 $userName["user_id"]
1563 );
1564 }
1565
1566 public static function getAssignmentParticipants(
1567 int $a_exercise_id,
1568 int $a_ass_id
1569 ): array {
1570 global $DIC;
1571
1572 $ilDB = $DIC->database();
1573
1574 $participants = array();
1575 $query = "SELECT user_id FROM exc_returned WHERE ass_id = " .
1576 $ilDB->quote($a_ass_id, "integer") .
1577 " AND obj_id = " .
1578 $ilDB->quote($a_exercise_id, "integer");
1579
1580 $res = $ilDB->query($query);
1581
1582 while ($row = $ilDB->fetchAssoc($res)) {
1583 $participants[] = $row['user_id'];
1584 }
1585
1586 return $participants;
1587 }
1588}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$filename
Definition: buildRTE.php:78
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)
@classDescription Date and time handling
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getAssignmentTeamMap(int $a_ass_id)
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 lookupType(int $a_id)
getType()
Get type this will most probably become an non public function in the future (or become obsolete)
const TYPE_UPLOAD
direct checks against const should be avoided, use type objects instead
static lookupTitle(int $a_id)
Exercise peer review.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static deleteUser(int $a_exc_id, int $a_user_id)
Delete all delivered files of user.
addResourceObject(string $a_wsp_id, string $a_text=null)
Add personal resource or repository object (ref_id) to assigment.
lookupNewFiles(int $a_tutor=null)
Check how much files have been uploaded by the learner after the last download of the tutor.
ilExcAssMemberState $state
static lookupExerciseIdForReturnedId(int $a_returned_id)
Get exercise from submission id (used in ilObjMediaObject)
getFiles(array $a_file_ids=null, bool $a_only_valid=false, string $a_min_timestamp=null, bool $print_versions=false)
Get submission items (not only files)
__construct(ilExAssignment $a_ass, int $a_user_id, ilExAssignmentTeam $a_team=null, bool $a_is_tutor=false, bool $a_public_submissions=false)
ilExPeerReview $peer_review
ilGlobalTemplateInterface $main_tpl
uploadFile(array $a_http_post_files, bool $unzip=false)
Save submitted file of user.
static downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members, string $to_path)
Download all submitted files of an assignment (all user)
downloadSingleFile(int $a_user_id, string $filename, string $filetitle, int $a_team_id=0)
processUploadedZipFile(string $fileTmp)
processes error handling etc for uploaded archive
ilExAssignmentTeam $team
static getAssignmentFilesByUsers(int $a_exc_id, int $a_ass_id, array $a_users)
ilExAssignment $assignment
getLastOpeningHTMLView()
TODO -> get rid of getTableUserWhere and move to repository class Get a mysql timestamp from the last...
deleteSelectedFiles(array $file_id_array)
Deletes already delivered files.
static getAllAssignmentFiles(int $a_exc_id, int $a_ass_id)
downloadMultipleFiles(array $a_filenames, ?int $a_user_id, bool $a_multi_user=false)
static getAssignmentParticipants(int $a_exercise_id, int $a_ass_id)
static findUserFiles(int $a_user_id, string $a_filetitle)
Check if given file was assigned Used in Blog/Portfolio.
ilExAssignmentTypeInterface $ass_type
updateTextSubmission(string $a_text)
Handle text assignment submissions.
isInTeam(int $a_user_id=null)
downloadFiles(array $a_file_ids=null, bool $a_only_new=false, bool $a_peer_review_mask_filename=false)
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
getTableUserWhere(bool $a_team_mode=false)
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 deliverFileLegacy(string $a_file, ?string $a_filename=null, ?string $a_mime=null, ?bool $isInline=false, ?bool $removeAfterDelivery=false, ?bool $a_exit_after=true)
static utf8_encode(string $string)
utf8-encodes string if it is not a valid utf8-string.
static unzip(string $path_to_zip_file, bool $overwrite_existing=false, bool $unpack_flat=false)
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 makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
static processZipFile(string $a_directory, string $a_file, bool $structure)
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static dirsize(string $directory)
get size of a directory or a file.
static getValidFilename(string $a_filename)
language handling
static getLogger(string $a_component_id)
Get component logger.
User class.
static _lookupName(int $a_user_id)
lookup user name
static _lookupType(int $id, bool $reference=false)
static _lookupObjId(int $ref_id)
static _lookupTitle(int $obj_id)
static escapeShellArg(string $a_arg)
static now()
Return current timestamp in Y-m-d H:i:s format.
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
$valid
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
Interface ilDBInterface.
quote($value, string $type)
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...
exit
Definition: login.php:28
$path
Definition: ltiservices.php:32
$res
Definition: ltiservices.php:69
$i
Definition: metadata.php:41
string $key
Consumer key/client ID value.
Definition: System.php:193
$query
$log
Definition: result.php:33
$lng