ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilExSubmission.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
11{
12 protected $assignment; // [ilExAssignment]
13 protected $user_id; // [int]
14 protected $team; // [ilExAssignmentTeam]
15 protected $peer_review; // [ilExPeerReview]
16 protected $is_tutor; // [bool]
17 protected $public_submissions; // [bool]
18
19 public function __construct(ilExAssignment $a_ass, $a_user_id, ilExAssignmentTeam $a_team = null, $a_is_tutor = false, $a_public_submissions = false)
20 {
21 global $ilUser;
22
23 $this->assignment = $a_ass;
24 $this->user_id = $a_user_id;
25 $this->is_tutor = (bool)$a_is_tutor;
26 $this->public_submissions = (bool)$a_public_submissions;
27
28 if($a_ass->hasTeam())
29 {
30 if(!$a_team)
31 {
32 include_once "Modules/Exercise/classes/class.ilExAssignmentTeam.php";
33 $this->team = ilExAssignmentTeam::getInstanceByUserId($this->assignment->getId(), $this->user_id);
34 }
35 else
36 {
37 $this->team = $a_team;
38 }
39 }
40
41 if($this->assignment->getPeerReview())
42 {
43 include_once "Modules/Exercise/classes/class.ilExPeerReview.php";
44 $this->peer_review = new ilExPeerReview($this->assignment);
45 }
46 }
47
48 public function getSubmissionType()
49 {
50 switch($this->assignment->getType())
51 {
54 return "File";
55
58 return "Object";
59
61 return "Text";
62 };
63 }
64
65
69 public function getAssignment()
70 {
71 return $this->assignment;
72 }
73
77 public function getTeam()
78 {
79 return $this->team;
80 }
81
85 public function getPeerReview()
86 {
87 return $this->peer_review;
88 }
89
90 public function validatePeerReviews()
91 {
92 $res = array();
93 foreach($this->getUserIds() as $user_id)
94 {
95 $valid = true;
96
97 // no peer review == valid
98 if($this->peer_review)
99 {
100 $valid = $this->peer_review->isFeedbackValidForPassed($user_id);
101 }
102
104 }
105 return $res;
106 }
107
108 public function getUserId()
109 {
110 return $this->user_id;
111 }
112
113 public function getUserIds()
114 {
115 if($this->team &&
116 !$this->hasNoTeamYet())
117 {
118 return $this->team->getMembers();
119 }
120
121 // if has no team currently there still might be uploads attached
122 return array($this->user_id);
123 }
124
125 public function getFeedbackId()
126 {
127 if($this->team)
128 {
129 return "t".$this->team->getId();
130 }
131 else
132 {
133 return $this->getUserId();
134 }
135 }
136
137 public function hasSubmitted()
138 {
139 return (bool)sizeof($this->getFiles(null, true));
140 }
141
142 public function getSelectedObject()
143 {
144 $files = $this->getFiles();
145 if(sizeof($files))
146 {
147 return array_pop($files);
148 }
149 }
150
151 public function canSubmit()
152 {
153 return ($this->isOwner() &&
154 !$this->assignment->notStartedYet() &&
155 $this->assignment->beforeDeadline());
156 }
157
158 public function canView()
159 {
160 global $ilUser;
161
162 if($this->canSubmit() ||
163 $this->isTutor() ||
164 $this->isInTeam() ||
165 $this->public_submissions)
166 {
167 return true;
168 }
169
170 // #16115
171 if($this->peer_review)
172 {
173 // peer review givers may view peer submissions
174 foreach($this->peer_review->getPeerReviewsByPeerId($this->getUserId()) as $giver)
175 {
176 if($giver["giver_id"] == $ilUser->getId())
177 {
178 return true;
179 }
180 }
181 }
182
183 return false;
184 }
185
186 public function isTutor()
187 {
188 return $this->is_tutor;
189 }
190
191 public function hasNoTeamYet()
192 {
193 if($this->assignment->hasTeam() &&
194 !$this->team->getId())
195 {
196 return true;
197 }
198 return false;
199 }
200
201 public function isInTeam($a_user_id = null)
202 {
203 global $ilUser;
204
205 if(!$a_user_id)
206 {
207 $a_user_id = $ilUser->getId();
208 }
209 return in_array($a_user_id, $this->getUserIds());
210 }
211
212 public function isOwner()
213 {
214 global $ilUser;
215
216 return ($ilUser->getId() == $this->getUserId());
217 }
218
219 public function hasPeerReviewAccess()
220 {
221 return ($this->peer_review &&
222 $this->peer_review->hasPeerReviewAccess($this->user_id));
223 }
224
225 public function canAddFile()
226 {
227 if(!$this->canSubmit())
228 {
229 return false;
230 }
231
232 $max = $this->getAssignment()->getMaxFile();
233 if($max &&
234 $max <= sizeof($this->getFiles()))
235 {
236 return false;
237 }
238
239 return true;
240 }
241
242
243 //
244 // FILES
245 //
246
247 protected function isLate()
248 {
249 $dl = $this->assignment->getPersonalDeadline($this->getUserId());
250 return ($dl && $dl < time());
251 }
252
253 protected function initStorage()
254 {
255 include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
256 return new ilFSStorageExercise($this->assignment->getExerciseId(), $this->assignment->getId());
257 }
258
262 function uploadFile($a_http_post_files, $unzip = false)
263 {
264 global $ilDB;
265
266 if(!$this->canAddFile())
267 {
268 return false;
269 }
270
271 $deliver_result = $this->initStorage()->uploadFile($a_http_post_files, $this->getUserId(), $unzip);
272
273 if ($deliver_result)
274 {
275 $next_id = $ilDB->nextId("exc_returned");
276 $query = sprintf("INSERT INTO exc_returned ".
277 "(returned_id, obj_id, user_id, filename, filetitle, mimetype, ts, ass_id, late) ".
278 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)",
279 $ilDB->quote($next_id, "integer"),
280 $ilDB->quote($this->assignment->getExerciseId(), "integer"),
281 $ilDB->quote($this->getUserId(), "integer"),
282 $ilDB->quote($deliver_result["fullname"], "text"),
283 $ilDB->quote(ilFileUtils::getValidFilename($a_http_post_files["name"]), "text"),
284 $ilDB->quote($deliver_result["mimetype"], "text"),
285 $ilDB->quote(ilUtil::now(), "timestamp"),
286 $ilDB->quote($this->assignment->getId(), "integer"),
287 $ilDB->quote($this->isLate(), "integer")
288 );
289 $ilDB->manipulate($query);
290
291 if($this->team)
292 {
293 $this->team->writeLog(ilExAssignmentTeam::TEAM_LOG_ADD_FILE,
294 $a_http_post_files["name"]);
295 }
296
297 return true;
298 }
299 }
300
305 function processUploadedZipFile($fileTmp)
306 {
307 global $lng;
308
309 // Create unzip-directory
310 $newDir = ilUtil::ilTempnam();
311 ilUtil::makeDir($newDir);
312
313 include_once ("Services/Utilities/classes/class.ilFileUtils.php");
314
315 $success = true;
316
317 try
318 {
319 ilFileUtils::processZipFile($newDir,$fileTmp, false);
320 ilFileUtils::recursive_dirscan($newDir, $filearray);
321
322 // #18441 - check number of files in zip
323 $max_num = $this->assignment->getMaxFile();
324 if($max_num)
325 {
326 $current_num = sizeof($this->getFiles());
327 $zip_num = sizeof($filearray["file"]);
328 if($current_num + $zip_num > $max_num)
329 {
330 $success = false;
331 ilUtil::sendFailure($lng->txt("exc_upload_error"), true);
332 }
333 }
334
335 if($success)
336 {
337 foreach ($filearray["file"] as $key => $filename)
338 {
339 $a_http_post_files["name"] = ilFileUtils::utf8_encode($filename);
340 $a_http_post_files["type"] = "other";
341 $a_http_post_files["tmp_name"] = $filearray["path"][$key]."/".$filename;
342 $a_http_post_files["error"] = 0;
343 $a_http_post_files["size"] = filesize($filearray["path"][$key]."/".$filename);
344
345 if(!$this->uploadFile($a_http_post_files, true))
346 {
347 $success = false;
348 ilUtil::sendFailure($lng->txt("exc_upload_error"), true);
349 }
350 }
351 }
352 }
353 catch (ilFileUtilsException $e)
354 {
355 $success = false;
356 ilUtil::sendFailure($e->getMessage());
357 }
358
359 ilUtil::delDir($newDir);
360 return $success;
361 }
362
363 public static function hasAnySubmissions($a_ass_id)
364 {
365 global $ilDB;
366
367 $query = "SELECT * FROM exc_returned".
368 " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
369 " AND (filename IS NOT NULL OR atext IS NOT NULL)".
370 " AND ts IS NOT NULL";
371 $res = $ilDB->query($query);
372 return $res->numRows($res);
373 }
374
375 public static function getAllAssignmentFiles($a_exc_id, $a_ass_id)
376 {
377 global $ilDB;
378
379 include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
380 $storage = new ilFSStorageExercise($a_exc_id, $a_ass_id);
381 $path = $storage->getAbsoluteSubmissionPath();
382
383 $query = "SELECT * FROM exc_returned WHERE ass_id = ".
384 $ilDB->quote($a_ass_id, "integer");
385
386 $res = $ilDB->query($query);
387 while($row = $ilDB->fetchAssoc($res))
388 {
389 $row["timestamp"] = $row["ts"];
390 $row["filename"] = $path."/".$row["user_id"]."/".basename($row["filename"]);
391 $delivered[] = $row;
392 }
393
394 return $delivered ? $delivered : array();
395 }
396
397 function getFiles(array $a_file_ids = null, $a_only_valid = false, $a_min_timestamp = null)
398 {
399 global $ilDB;
400
401 $sql = "SELECT * FROM exc_returned".
402 " WHERE ass_id = ".$ilDB->quote($this->getAssignment()->getId(), "integer").
403 " AND ".$ilDB->in("user_id", $this->getUserIds(), "", "integer");
404
405 if($a_file_ids)
406 {
407 $sql .= " AND ".$ilDB->in("returned_id", $a_file_ids, false, "integer");
408 }
409
410 if($a_min_timestamp)
411 {
412 $sql .= " AND ts > ".$ilDB->quote($a_min_timestamp, "timestamp");
413 }
414
415 $result = $ilDB->query($sql);
416
417 $delivered_files = array();
418 if ($ilDB->numRows($result))
419 {
420 $path = $this->initStorage()->getAbsoluteSubmissionPath();
421
422 while ($row = $ilDB->fetchAssoc($result))
423 {
424 // blog/portfolio/text submissions
425 if($a_only_valid &&
426 !$row["filename"] &&
427 !(trim($row["atext"])))
428 {
429 continue;
430 }
431
432 $row["owner_id"] = $row["user_id"];
433 $row["timestamp"] = $row["ts"];
434 $row["timestamp14"] = substr($row["ts"], 0, 4).
435 substr($row["ts"], 5, 2).substr($row["ts"], 8, 2).
436 substr($row["ts"], 11, 2).substr($row["ts"], 14, 2).
437 substr($row["ts"], 17, 2);
438 $row["filename"] = $path.
439 "/".$row["user_id"]."/".basename($row["filename"]);
440
441 // see 22301, 22719
442 if (is_file($row["filename"]) || (!in_array($this->assignment->getType(),
444 {
445 array_push($delivered_files, $row);
446 }
447 }
448 }
449
450 return $delivered_files;
451 }
452
457 function lookupNewFiles()
458 {
459 global $ilDB, $ilUser;
460
461 $q = "SELECT exc_returned.returned_id AS id ".
462 "FROM exc_usr_tutor, exc_returned ".
463 "WHERE exc_returned.ass_id = exc_usr_tutor.ass_id ".
464 " AND exc_returned.user_id = exc_usr_tutor.usr_id ".
465 " AND exc_returned.ass_id = ".$ilDB->quote($this->getAssignment()->getId(), "integer").
466 " AND ".$ilDB->in("exc_returned.user_id", $this->getUserIds(), "", "integer").
467 " AND exc_usr_tutor.tutor_id = ".$ilDB->quote($ilUser->getId(), "integer").
468 " AND exc_usr_tutor.download_time < exc_returned.ts ";
469
470 $new_up_set = $ilDB->query($q);
471
472 $new_up = array();
473 while ($new_up_rec = $ilDB->fetchAssoc($new_up_set))
474 {
475 $new_up[] = $new_up_rec["id"];
476 }
477
478 return $new_up;
479 }
480
487 public static function lookupExerciseIdForReturnedId($a_returned_id)
488 {
489 global $ilDB;
490
491 $set = $ilDB->query("SELECT obj_id".
492 " FROM exc_returned".
493 " WHERE returned_id = ".$ilDB->quote($a_returned_id, "integer"));
494 $row = $ilDB->fetchAssoc($set);
495 return (int)$row["obj_id"];
496 }
497
506 public static function findUserFiles($a_user_id, $a_filetitle)
507 {
508 global $ilDB;
509
510 $set = $ilDB->query("SELECT obj_id, ass_id".
511 " FROM exc_returned".
512 " WHERE user_id = ".$ilDB->quote($a_user_id, "integer").
513 " AND filetitle = ".$ilDB->quote($a_filetitle, "text"));
514 $res = array();
515 while($row = $ilDB->fetchAssoc($set))
516 {
517 $res[$row["ass_id"]] = $row;
518 }
519 return $res;
520 }
521
522 function deleteAllFiles()
523 {
524 $files = array();
525 foreach($this->getFiles() as $item)
526 {
527 $files[] = $item["returned_id"];
528 }
529 if(sizeof($files))
530 {
532 }
533 }
534
541 function deleteSelectedFiles(array $file_id_array)
542 {
543 global $ilDB;
544
545 $user_ids = $this->getUserIds();
546 if(!$user_ids ||
547 !sizeof($file_id_array))
548 {
549 return;
550 }
551
552 if (count($file_id_array))
553 {
554 $result = $ilDB->query("SELECT * FROM exc_returned".
555 " WHERE ".$ilDB->in("returned_id", $file_id_array, false, "integer").
556 " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
557
558 if ($ilDB->numRows($result))
559 {
560 $result_array = array();
561 while ($row = $ilDB->fetchAssoc($result))
562 {
563 $row["timestamp"] = $row["ts"];
564 array_push($result_array, $row);
565 }
566
567 // delete the entries in the database
568 $ilDB->manipulate("DELETE FROM exc_returned".
569 " WHERE ".$ilDB->in("returned_id", $file_id_array, false, "integer").
570 " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
571
572 // delete the files
573 $path = $this->initStorage()->getAbsoluteSubmissionPath();
574 foreach ($result_array as $key => $value)
575 {
576 if($value["filename"])
577 {
578 if($this->team)
579 {
580 $this->team->writeLog(ilExAssignmentTeam::TEAM_LOG_REMOVE_FILE,
581 $value["filetitle"]);
582 }
583
584 $filename = $path."/".$value["user_id"]."/".basename($value["filename"]);
585 unlink($filename);
586 }
587 }
588 }
589 }
590 }
591
598 public static function deleteUser($a_exc_id, $a_user_id)
599 {
600
601 include_once("./Modules/Exercise/classes/class.ilExAssignment.php");
602
603 foreach(ilExAssignment::getInstancesByExercise($a_exc_id) as $ass)
604 {
605 $submission = new self($ass, $a_user_id);
606 $submission->deleteAllFiles();
607
608 // remove from any team
609 $team = $submission->getTeam();
610 if($team)
611 {
612 $team->removeTeamMember($a_user_id);
613 }
614
615 // #14900
616 $member_status = $ass->getMemberStatus($a_user_id);
617 $member_status->setStatus("notgraded");
618 $member_status->update();
619 }
620 }
621
622 protected function getLastDownloadTime(array $a_user_ids)
623 {
624 global $ilDB, $ilUser;
625
626 $q = "SELECT download_time FROM exc_usr_tutor WHERE ".
627 " ass_id = ".$ilDB->quote($this->getAssignment()->getId(), "integer")." AND ".
628 $ilDB->in("usr_id", $a_user_ids, "", "integer")." AND ".
629 " tutor_id = ".$ilDB->quote($ilUser->getId(), "integer");
630 $lu_set = $ilDB->query($q);
631 $lu_rec = $ilDB->fetchAssoc($lu_set);
632 return $lu_rec["download_time"];
633 }
634
635 function downloadFiles(array $a_file_ids = null, $a_only_new = false, $a_peer_review_mask_filename = false)
636 {
637 global $ilUser, $lng;
638
639 $user_ids = $this->getUserIds();
640 $is_team = $this->assignment->hasTeam();
641
642 // get last download time
643 $download_time = null;
644 if ($a_only_new)
645 {
646 $download_time = $this->getLastDownloadTime($user_ids);
647 }
648
649 if($this->is_tutor)
650 {
651 $this->updateTutorDownloadTime();
652 }
653
654 if($a_peer_review_mask_filename)
655 {
656 // process peer review sequence id
657 $peer_id = null;
658 foreach($this->peer_review->getPeerReviewsByGiver($ilUser->getId()) as $idx => $item)
659 {
660 if($item["peer_id"] == $this->getUserId())
661 {
662 $peer_id = $idx+1;
663 break;
664 }
665 }
666
667 // this will remove personal info from zip-filename
668 $is_team = true;
669 }
670
671 $files = $this->getFiles($a_file_ids, false, $download_time);
672 if($files)
673 {
674 if (sizeof($files) == 1)
675 {
676 $file = array_pop($files);
677
678 switch($this->assignment->getType())
679 {
682 $file["filetitle"] = ilObjUser::_lookupName($file["user_id"]);
683 $file["filetitle"] = ilObject::_lookupTitle($this->assignment->getExerciseId())." - ".
684 $this->assignment->getTitle()." - ".
685 $file["filetitle"]["firstname"]." ".
686 $file["filetitle"]["lastname"]." (".
687 $file["filetitle"]["login"].").zip";
688 break;
689
690 default:
691 break;
692 }
693
694 if($a_peer_review_mask_filename)
695 {
696 $suffix = array_pop(explode(".", $file["filetitle"]));
697 $file["filetitle"] = $this->assignment->getTitle()."_peer".$peer_id.".".$suffix;
698 }
699 else if($file["late"])
700 {
701 $file["filetitle"] = $lng->txt("exc_late_submission")." - ".
702 $file["filetitle"];
703 }
704
705 $this->downloadSingleFile($file["user_id"], $file["filename"], $file["filetitle"]);
706 }
707 else
708 {
709 $array_files = array();
710 foreach($files as $seq => $file)
711 {
712 $src = basename($file["filename"]);
713 if($a_peer_review_mask_filename)
714 {
715 $suffix = array_pop(explode(".", $src));
716 $tgt = $this->assignment->getTitle()."_peer".$peer_id.
717 "_".(++$seq).".".$suffix;
718
719 $array_files[$file["user_id"]][] = array(
720 "src" => $src,
721 "tgt" => $tgt
722 );
723 }
724 else
725 {
726 $array_files[$file["user_id"]][] = array(
727 "src" => $src,
728 "late" => $file["late"]
729 );
730 }
731 }
732
733 $this->downloadMultipleFiles($array_files,
734 ($is_team ? null : $this->getUserId()), $is_team);
735 }
736 }
737 else
738 {
739 return false;
740 }
741
742 return true;
743 }
744
745 // Update the timestamp of the last download of current user (=tutor)
746 public function updateTutorDownloadTime()
747 {
748 global $ilUser, $ilDB;
749
750 $exc_id = $this->assignment->getExerciseId();
751 $ass_id = $this->assignment->getId();
752
753 foreach($this->getUserIds() as $user_id)
754 {
755 $ilDB->manipulateF("DELETE FROM exc_usr_tutor ".
756 "WHERE ass_id = %s AND usr_id = %s AND tutor_id = %s",
757 array("integer", "integer", "integer"),
758 array($ass_id, $user_id, $ilUser->getId()));
759
760 $ilDB->manipulateF("INSERT INTO exc_usr_tutor (ass_id, obj_id, usr_id, tutor_id, download_time) VALUES ".
761 "(%s, %s, %s, %s, %s)",
762 array("integer", "integer", "integer", "integer", "timestamp"),
763 array($ass_id, $exc_id, $user_id, $ilUser->getId(), ilUtil::now()));
764 }
765 }
766
767 protected function downloadSingleFile($a_user_id, $filename, $filetitle)
768 {
769 $filename = $this->initStorage()->getAbsoluteSubmissionPath().
770 "/".$a_user_id."/".basename($filename);
771
772 ilUtil::deliverFile($filename, $filetitle);
773 }
774
775 protected function downloadMultipleFiles($a_filenames, $a_user_id, $a_multi_user = false)
776 {
777 global $lng;
778
779 $path = $this->initStorage()->getAbsoluteSubmissionPath();
780
781 $cdir = getcwd();
782
783 $zip = PATH_TO_ZIP;
784 $tmpdir = ilUtil::ilTempnam();
785 $tmpfile = ilUtil::ilTempnam();
786 $tmpzipfile = $tmpfile . ".zip";
787
788 ilUtil::makeDir($tmpdir);
789 chdir($tmpdir);
790
791 $assTitle = ilExAssignment::lookupTitle($this->assignment->getId());
792 $deliverFilename = str_replace(" ", "_", $assTitle);
793 if ($a_user_id > 0 && !$a_multi_user)
794 {
795 $userName = ilObjUser::_lookupName($a_user_id);
796 $deliverFilename .= "_".$userName["lastname"]."_".$userName["firstname"];
797 }
798 else
799 {
800 $deliverFilename .= "_files";
801 }
802 $orgDeliverFilename = trim($deliverFilename);
803 $deliverFilename = ilUtil::getASCIIFilename($orgDeliverFilename);
804 ilUtil::makeDir($tmpdir."/".$deliverFilename);
805 chdir($tmpdir."/".$deliverFilename);
806
807 //copy all files to a temporary directory and remove them afterwards
808 $parsed_files = $duplicates = array();
809 foreach ($a_filenames as $user_id => $files)
810 {
811 $pathname = $path."/".$user_id;
812
813 foreach($files as $filename)
814 {
815 // peer review masked filenames, see deliverReturnedFiles()
816 if(isset($filename["tgt"]))
817 {
818 $newFilename = $filename["tgt"];
819 $filename = $filename["src"];
820 }
821 else
822 {
823 $late = $filename["late"];
824 $filename = $filename["src"];
825
826 // remove timestamp
827 $newFilename = trim($filename);
828 $pos = strpos($newFilename , "_");
829 if ($pos !== false)
830 {
831 $newFilename = substr($newFilename, $pos + 1);
832 }
833 // #11070
834 $chkName = strtolower($newFilename);
835 if(array_key_exists($chkName, $duplicates))
836 {
837 $suffix = strrpos($newFilename, ".");
838 $newFilename = substr($newFilename, 0, $suffix).
839 " (".(++$duplicates[$chkName]).")".
840 substr($newFilename, $suffix);
841 }
842 else
843 {
844 $duplicates[$chkName] = 1;
845 }
846
847 if($late)
848 {
849 $newFilename = $lng->txt("exc_late_submission")." - ".
850 $newFilename;
851 }
852 }
853
854 $newFilename = ilUtil::getASCIIFilename($newFilename);
855 $newFilename = $tmpdir.DIRECTORY_SEPARATOR.$deliverFilename.DIRECTORY_SEPARATOR.$newFilename;
856 // copy to temporal directory
857 $oldFilename = $pathname.DIRECTORY_SEPARATOR.$filename;
858 if (!copy ($oldFilename, $newFilename))
859 {
860 echo 'Could not copy '.$oldFilename.' to '.$newFilename;
861 }
862 touch($newFilename, filectime($oldFilename));
863 $parsed_files[] = ilUtil::escapeShellArg($deliverFilename.DIRECTORY_SEPARATOR.basename($newFilename));
864 }
865 }
866
867 chdir($tmpdir);
868 $zipcmd = $zip." ".ilUtil::escapeShellArg($tmpzipfile)." ".join($parsed_files, " ");
869
870 exec($zipcmd);
871 ilUtil::delDir($tmpdir);
872
873 chdir($cdir);
874 ilUtil::deliverFile($tmpzipfile, $orgDeliverFilename.".zip", "", false, true);
875 exit;
876 }
877
884 public static function downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members)
885 {
886 global $lng;
887
888 include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
889
890 $storage = new ilFSStorageExercise($a_ass->getExerciseId(), $a_ass->getId());
891 $storage->create();
892
893 ksort($members);
894 //$savepath = $this->getExercisePath() . "/" . $this->obj_id . "/";
895 $savepath = $storage->getAbsoluteSubmissionPath();
896 $cdir = getcwd();
897
898
899 // important check: if the directory does not exist
900 // ILIAS stays in the current directory (echoing only a warning)
901 // and the zip command below archives the whole ILIAS directory
902 // (including the data directory) and sends a mega file to the user :-o
903 if (!is_dir($savepath))
904 {
905 return;
906 }
907 // Safe mode fix
908// chdir($this->getExercisePath());
909 chdir($storage->getTempPath());
910 $zip = PATH_TO_ZIP;
911
912 // check first, if we have enough free disk space to copy all files to temporary directory
913 $tmpdir = ilUtil::ilTempnam();
914 ilUtil::makeDir($tmpdir);
915 chdir($tmpdir);
916
917 // check free diskspace
918 $dirsize = 0;
919 foreach (array_keys($members) as $id)
920 {
921 $directory = $savepath.DIRECTORY_SEPARATOR.$id;
922 $dirsize += ilUtil::dirsize($directory);
923 }
924 if ($dirsize > disk_free_space($tmpdir))
925 {
926 return -1;
927 }
928
929 $ass_type = $a_ass->getType();
930
931 // copy all member directories to the temporary folder
932 // switch from id to member name and append the login if the member name is double
933 // ensure that no illegal filenames will be created
934 // remove timestamp from filename
935 if($a_ass->hasTeam())
936 {
937 $team_dirs = array();
938 $team_map = ilExAssignmentTeam::getAssignmentTeamMap($a_ass->getId());
939 }
940 foreach ($members as $id => $item)
941 {
942 $user = $item["name"];
943 $user_files = $item["files"];
944
945 $sourcedir = $savepath.DIRECTORY_SEPARATOR.$id;
946 if (!is_dir($sourcedir))
947 {
948 continue;
949 }
950
951 $userName = ilObjUser::_lookupName($id);
952
953 // group by teams
954 $team_dir= "";
955 if(is_array($team_map) &&
956 array_key_exists($id, $team_map))
957 {
958 $team_id = $team_map[$id];
959 if(!array_key_exists($team_id, $team_dirs))
960 {
961 $team_dir = $lng->txt("exc_team")." ".$team_id;
962 ilUtil::makeDir($team_dir);
963 $team_dirs[$team_id] = $team_dir;
964 }
965 $team_dir = $team_dirs[$team_id].DIRECTORY_SEPARATOR;
966 }
967
968 $targetdir = $team_dir.ilUtil::getASCIIFilename(
969 trim($userName["lastname"])."_".
970 trim($userName["firstname"])."_".
971 trim($userName["login"])."_".
972 $userName["user_id"]
973 );
974 ilUtil::makeDir($targetdir);
975
976 $sourcefiles = scandir($sourcedir);
977 $duplicates = array();
978 foreach ($sourcefiles as $sourcefile) {
979 if ($sourcefile == "." || $sourcefile == "..")
980 {
981 continue;
982 }
983
984 $targetfile = trim(basename($sourcefile));
985 $pos = strpos($targetfile, "_");
986 if ($pos !== false)
987 {
988 $targetfile= substr($targetfile, $pos + 1);
989 }
990
991 // #14536
992 if(array_key_exists($targetfile, $duplicates))
993 {
994 $suffix = strrpos($targetfile, ".");
995 $targetfile = substr($targetfile, 0, $suffix).
996 " (".(++$duplicates[$targetfile]).")".
997 substr($targetfile, $suffix);
998 }
999 else
1000 {
1001 $duplicates[$targetfile] = 1;
1002 }
1003
1004 // late submission?
1005 foreach($user_files as $file)
1006 {
1007 if(basename($file["filename"]) == $sourcefile)
1008 {
1009 if($file["late"])
1010 {
1011 $targetfile = $lng->txt("exc_late_submission")." - ".
1012 $targetfile;
1013 }
1014 break;
1015 }
1016 }
1017
1018 $targetfile = ilUtil::getASCIIFilename($targetfile);
1019 $targetfile = $targetdir.DIRECTORY_SEPARATOR.$targetfile;
1020 $sourcefile = $sourcedir.DIRECTORY_SEPARATOR.$sourcefile;
1021
1022 if (!copy ($sourcefile, $targetfile))
1023 {
1024 include_once "Modules/Exercise/exceptions/class.ilExerciseException.php";
1025 throw new ilExerciseException("Could not copy ".basename($sourcefile)." to '".$targetfile."'.");
1026 }
1027 else
1028 {
1029 // preserve time stamp
1030 touch($targetfile, filectime($sourcefile));
1031
1032 // blogs and portfolios are stored as zip and have to be unzipped
1033 if($ass_type == ilExAssignment::TYPE_PORTFOLIO ||
1034 $ass_type == ilExAssignment::TYPE_BLOG)
1035 {
1036 ilUtil::unzip($targetfile);
1037 unlink($targetfile);
1038 }
1039 }
1040
1041 }
1042 }
1043
1044 $tmpfile = ilUtil::ilTempnam();
1045 $tmpzipfile = $tmpfile . ".zip";
1046 // Safe mode fix
1047 $zipcmd = $zip." -r ".ilUtil::escapeShellArg($tmpzipfile)." .";
1048 exec($zipcmd);
1049 ilUtil::delDir($tmpdir);
1050
1051 $assTitle = $a_ass->getTitle()."_".$a_ass->getId();
1052 chdir($cdir);
1053 ilUtil::deliverFile($tmpzipfile, (strlen($assTitle) == 0
1054 ? strtolower($lng->txt("exc_assignment"))
1055 : $assTitle). ".zip", "", false, true);
1056 }
1057
1064 {
1065 global $ilDB;
1066
1067 $ilDB->setLimit(1);
1068
1069 $q = "SELECT obj_id,user_id,ts FROM exc_returned".
1070 " WHERE ass_id = ".$ilDB->quote($this->assignment->getId(), "integer").
1071 " AND ".$ilDB->in("user_id", $this->getUserIds(), "", "integer").
1072 " AND (filename IS NOT NULL OR atext IS NOT NULL)".
1073 " AND ts IS NOT NULL".
1074 " ORDER BY ts DESC";
1075 $usr_set = $ilDB->query($q);
1076 $array = $ilDB->fetchAssoc($usr_set);
1077 return ilUtil::getMySQLTimestamp($array["ts"]);
1078 }
1079
1080
1081 //
1082 // OBJECTS
1083 //
1084
1091 function addResourceObject($a_wsp_id, $a_text = null)
1092 {
1093 global $ilDB;
1094
1095 $next_id = $ilDB->nextId("exc_returned");
1096 $query = sprintf("INSERT INTO exc_returned ".
1097 "(returned_id, obj_id, user_id, filetitle, ass_id, ts, atext, late) ".
1098 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
1099 $ilDB->quote($next_id, "integer"),
1100 $ilDB->quote($this->assignment->getExerciseId(), "integer"),
1101 $ilDB->quote($this->getUserId(), "integer"),
1102 $ilDB->quote($a_wsp_id, "text"),
1103 $ilDB->quote($this->assignment->getId(), "integer"),
1104 $ilDB->quote(ilUtil::now(), "timestamp"),
1105 $ilDB->quote($a_text, "text"),
1106 $ilDB->quote($this->isLate(), "integer")
1107 );
1108 $ilDB->manipulate($query);
1109
1110 return $next_id;
1111 }
1112
1118 public function deleteResourceObject($a_returned_id)
1119 {
1120 global $ilDB;
1121
1122 $ilDB->manipulate("DELETE FROM exc_returned".
1123 " WHERE obj_id = ".$ilDB->quote($this->assignment->getExerciseId(), "integer").
1124 " AND user_id = ".$ilDB->quote($this->getUserId(), "integer").
1125 " AND ass_id = ".$ilDB->quote($this->assignment->getId(), "integer").
1126 " AND returned_id = ".$ilDB->quote($a_returned_id, "integer"));
1127 }
1128
1135 function updateTextSubmission($a_text)
1136 {
1137 global $ilDB;
1138
1139 $files = $this->getFiles();
1140
1141 // no text = remove submission
1142 if(!trim($a_text))
1143 {
1144 $this->deleteAllFiles();
1145 return;
1146 }
1147
1148 if(!$files)
1149 {
1150 return $this->addResourceObject("TEXT", $a_text);
1151 }
1152 else
1153 {
1154 $files = array_shift($files);
1155 $id = $files["returned_id"];
1156 if($id)
1157 {
1158 $ilDB->manipulate("UPDATE exc_returned".
1159 " SET atext = ".$ilDB->quote($a_text, "text").
1160 ", ts = ".$ilDB->quote(ilUtil::now(), "timestamp").
1161 ", late = ".$ilDB->quote($this->isLate(), "integer").
1162 " WHERE returned_id = ".$ilDB->quote($id, "integer"));
1163 return $id;
1164 }
1165 }
1166 }
1167
1168
1169 //
1170 // GUI helper
1171 //
1172
1173 // :TODO:
1174
1175 public function getDownloadedFilesInfoForTableGUIS($a_parent_obj, $a_parent_cmd = null)
1176 {
1177 global $lng, $ilCtrl;
1178
1179 $result = array();
1180 $result["files"]["count"] = "---";
1181
1182 // submission:
1183 // see if files have been resubmmited after solved
1184 $last_sub = $this->getLastSubmission();
1185 if ($last_sub)
1186 {
1187 $last_sub = ilDatePresentation::formatDate(new ilDateTime($last_sub,IL_CAL_DATETIME));
1188 }
1189 else
1190 {
1191 $last_sub = "---";
1192 }
1193 /* #13741 - status_time has been reduced to grading (mark/status)
1194 if (self::lookupUpdatedSubmission($a_ass_id, $a_user_id) == 1)
1195 {
1196 $last_sub = "<b>".$last_sub."</b>";
1197 }
1198 */
1199 $result["last_submission"]["txt"] = $lng->txt("exc_last_submission");
1200 $result["last_submission"]["value"] = $last_sub;
1201
1202 // #16994
1203 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", $this->getUserId());
1204
1205 // assignment type specific
1206 switch($this->assignment->getType())
1207 {
1209 // data is merged by team - see above
1210 // fallthrough
1211
1213 $all_files = $this->getFiles();
1214 $late_files = 0;
1215 foreach($all_files as $file)
1216 {
1217 if($file["late"])
1218 {
1219 $late_files++;
1220 }
1221 }
1222
1223 // nr of submitted files
1224 $result["files"]["txt"] = $lng->txt("exc_files_returned");
1225 if ($late_files)
1226 {
1227 $result["files"]["txt"].= ' - <span class="warning">'.$lng->txt("exc_late_submission")." (".$late_files.")</span>";
1228 }
1229 $sub_cnt = count($all_files);
1230 $new = $this->lookupNewFiles();
1231 if (count($new) > 0)
1232 {
1233 $sub_cnt.= " ".sprintf($lng->txt("cnt_new"),count($new));
1234 }
1235
1236 $result["files"]["count"] = $sub_cnt;
1237
1238 // download command
1239 if ($sub_cnt > 0)
1240 {
1241 $result["files"]["download_url"] =
1242 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1243
1244 if (count($new) <= 0)
1245 {
1246 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1247 }
1248 else
1249 {
1250 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_all_files");
1251 }
1252
1253 // download new files only
1254 if (count($new) > 0)
1255 {
1256 $result["files"]["download_new_url"] =
1257 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadNewReturned");
1258
1259 $result["files"]["download_new_txt"] = $lng->txt("exc_tbl_action_download_new_files");
1260 }
1261 }
1262 break;
1263
1265 $result["files"]["txt"] =$lng->txt("exc_blog_returned");
1266 $blogs = $this->getFiles();
1267 if($blogs)
1268 {
1269 $blogs = array_pop($blogs);
1270 if($blogs && substr($blogs["filename"], -1) != "/")
1271 {
1272 if($blogs["late"])
1273 {
1274 $result["files"]["txt"].= ' - <span class="warning">'.$lng->txt("exc_late_submission")."</span>";
1275 }
1276
1277 $result["files"]["count"] = 1;
1278
1279 $result["files"]["download_url"] =
1280 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1281
1282 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1283 }
1284 }
1285 break;
1286
1288 $result["files"]["txt"] = $lng->txt("exc_portfolio_returned");
1289 $portfolios = $this->getFiles();
1290 if($portfolios)
1291 {
1292 $portfolios = array_pop($portfolios);
1293 if($portfolios && substr($portfolios["filename"], -1) != "/")
1294 {
1295 if($portfolios["late"])
1296 {
1297 $result["files"]["txt"].= ' - <span class="warning">'.$lng->txt("exc_late_submission")."</span>";
1298 }
1299
1300 $result["files"]["count"] = 1;
1301
1302 $result["files"]["download_url"] =
1303 $ilCtrl->getLinkTargetByClass("ilexsubmissionfilegui", "downloadReturned");
1304
1305 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_download_files");
1306 }
1307 }
1308 break;
1309
1311 $result["files"]["txt"] = $lng->txt("exc_files_returned_text");
1312 $files = $this->getFiles();
1313 if($files)
1314 {
1315 $result["files"]["count"] = 1;
1316
1317 $files = array_shift($files);
1318 if(trim($files["atext"]))
1319 {
1320 if($files["late"])
1321 {
1322 $result["files"]["txt"].= ' - <span class="warning">'.$lng->txt("exc_late_submission")."</span>";
1323 }
1324
1325 $result["files"]["download_url"] =
1326 $ilCtrl->getLinkTargetByClass("ilexsubmissiontextgui", "showAssignmentText");
1327
1328 $result["files"]["download_txt"] = $lng->txt("exc_tbl_action_text_assignment_show");
1329 }
1330 }
1331 break;
1332 }
1333
1334 $ilCtrl->setParameterByClass("ilexsubmissionfilegui", "member_id", "");
1335
1336 return $result;
1337 }
1338}
1339
sprintf('%.4f', $callTime)
$result
$success
Definition: Utf8Test.php:86
$files
Definition: add-vimline.php:18
$path
Definition: aliased.php:25
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_DATETIME
static formatDate(ilDateTime $date)
Format a date @access public.
@classDescription Date and time handling
Exercise assignment team.
static getAssignmentTeamMap($a_ass_id)
Get team structure for assignment.
static getInstanceByUserId($a_assignment_id, $a_user_id, $a_create_on_demand=false)
Exercise assignment.
getExerciseId()
Get exercise id.
getId()
Get assignment id.
static getInstancesByExercise($a_exc_id)
static lookupTitle($a_id)
Lookup title.
Exercise peer review.
Exercise submission.
lookupNewFiles()
Check how much files have been uploaded by the learner after the last download of the tutor.
static deleteUser($a_exc_id, $a_user_id)
Delete all delivered files of user.
static getAllAssignmentFiles($a_exc_id, $a_ass_id)
downloadSingleFile($a_user_id, $filename, $filetitle)
processUploadedZipFile($fileTmp)
processes errorhandling etc for uploaded archive
addResourceObject($a_wsp_id, $a_text=null)
Add personal resource to assigment.
downloadMultipleFiles($a_filenames, $a_user_id, $a_multi_user=false)
isInTeam($a_user_id=null)
static lookupExerciseIdForReturnedId($a_returned_id)
Get exercise from submission id (used in ilObjMediaObject)
static hasAnySubmissions($a_ass_id)
static downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members)
Download all submitted files of an assignment (all user)
deleteSelectedFiles(array $file_id_array)
Deletes already delivered files.
__construct(ilExAssignment $a_ass, $a_user_id, ilExAssignmentTeam $a_team=null, $a_is_tutor=false, $a_public_submissions=false)
downloadFiles(array $a_file_ids=null, $a_only_new=false, $a_peer_review_mask_filename=false)
deleteResourceObject($a_returned_id)
Remove personal resource to assigment.
updateTextSubmission($a_text)
Handle text assignment submissions.
uploadFile($a_http_post_files, $unzip=false)
Save submitted file of user.
static findUserFiles($a_user_id, $a_filetitle)
Check if given file was assigned.
getDownloadedFilesInfoForTableGUIS($a_parent_obj, $a_parent_cmd=null)
getFiles(array $a_file_ids=null, $a_only_valid=false, $a_min_timestamp=null)
getLastSubmission()
Get the date of the last submission of a user for the assignment.
getLastDownloadTime(array $a_user_ids)
Class to report exception.
Class to report exception.
static getValidFilename($a_filename)
Get valid filename.
static processZipFile($a_directory, $a_file, $structure, $ref_id=null, $containerType=null, $tree=null, $access_handler=null)
unzips in given directory and processes uploaded zip for use as single files
static utf8_encode($string)
utf8-encodes string if it is not a valid utf8-string.
static recursive_dirscan($dir, &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
static _lookupName($a_user_id)
lookup user name
static _lookupTitle($a_id)
lookup object title
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static getMySQLTimestamp($a_ts)
Get MySQL timestamp in 4.1.x or higher format (yyyy-mm-dd hh:mm:ss) This function converts a timestam...
static escapeShellArg($a_arg)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static now()
Return current timestamp in Y-m-d H:i:s format.
static ilTempnam($a_temp_path=null)
Create a temporary file in an ILIAS writable directory.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static unzip($a_file, $overwrite=false, $a_flat=false)
unzip file
static deliverFile($a_file, $a_filename, $a_mime='', $isInline=false, $removeAfterDelivery=false, $a_exit_after=true)
deliver file for download via browser.
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
static dirsize($directory)
get size of a directory or a file.
$valid
global $ilCtrl
Definition: ilias.php:18
global $lng
Definition: privfeed.php:17
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file
global $ilDB
$ilUser
Definition: imgupload.php:18