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