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