ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilExAssignment.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_UPLOAD = 1;
14  const TYPE_BLOG = 2;
15  const TYPE_PORTFOLIO = 3;
16  const TYPE_UPLOAD_TEAM = 4;
17  const TYPE_TEXT = 5;
18 
22  const TEAM_LOG_ADD_FILE = 4;
24 
27 
28  protected $id;
29  protected $exc_id;
30  protected $type;
31  protected $start_time;
32  protected $deadline;
33  protected $instruction;
34  protected $title;
35  protected $mandatory;
36  protected $order_nr;
37  protected $peer;
38  protected $peer_min;
39  protected $peer_dl;
40  protected $peer_file;
41  protected $peer_personal;
42  protected $feedback_file;
43  protected $feedback_cron;
44  protected $feedback_date;
45 
49  function __construct($a_id = 0)
50  {
51  $this->setType(self::TYPE_UPLOAD);
52  $this->setFeedbackDate(self::FEEDBACK_DATE_DEADLINE);
53 
54  if ($a_id > 0)
55  {
56  $this->setId($a_id);
57  $this->read();
58  }
59  }
60 
66  function setId($a_val)
67  {
68  $this->id = $a_val;
69  }
70 
76  function getId()
77  {
78  return $this->id;
79  }
80 
86  function setExerciseId($a_val)
87  {
88  $this->exc_id = $a_val;
89  }
90 
96  function getExerciseId()
97  {
98  return $this->exc_id;
99  }
100 
106  function setStartTime($a_val)
107  {
108  $this->start_time = $a_val;
109  }
110 
116  function getStartTime()
117  {
118  return $this->start_time;
119  }
120 
126  function setDeadline($a_val)
127  {
128  $this->deadline = $a_val;
129  }
130 
136  function getDeadline()
137  {
138  return $this->deadline;
139  }
140 
146  function setInstruction($a_val)
147  {
148  $this->instruction = $a_val;
149  }
150 
156  function getInstruction()
157  {
158  return $this->instruction;
159  }
160 
166  function setTitle($a_val)
167  {
168  $this->title = $a_val;
169  }
170 
176  function getTitle()
177  {
178  return $this->title;
179  }
180 
186  function setMandatory($a_val)
187  {
188  $this->mandatory = $a_val;
189  }
190 
196  function getMandatory()
197  {
198  return $this->mandatory;
199  }
200 
206  function setOrderNr($a_val)
207  {
208  $this->order_nr = $a_val;
209  }
210 
216  function getOrderNr()
217  {
218  return $this->order_nr;
219  }
220 
226  function setType($a_value)
227  {
228  if($this->isValidType($a_value))
229  {
230  $this->type = (int)$a_value;
231 
232  if($this->type == self::TYPE_UPLOAD_TEAM)
233  {
234  $this->setPeerReview(false);
235  }
236  }
237  }
238 
244  function getType()
245  {
246  return $this->type;
247  }
248 
255  function isValidType($a_value)
256  {
257  if(in_array((int)$a_value, array(self::TYPE_UPLOAD, self::TYPE_BLOG,
258  self::TYPE_PORTFOLIO, self::TYPE_UPLOAD_TEAM, self::TYPE_TEXT)))
259  {
260  return true;
261  }
262  return false;
263  }
264 
270  function setPeerReview($a_value)
271  {
272  $this->peer = (bool)$a_value;
273  }
274 
280  function getPeerReview()
281  {
282  return (bool)$this->peer;
283  }
284 
290  function setPeerReviewMin($a_value)
291  {
292  $this->peer_min = (int)$a_value;
293  }
294 
300  function getPeerReviewMin()
301  {
302  return (int)$this->peer_min;
303  }
304 
310  function setPeerReviewDeadline($a_val)
311  {
312  $this->peer_dl = $a_val;
313  }
314 
321  {
322  return $this->peer_dl;
323  }
324 
330  function setPeerReviewFileUpload($a_val)
331  {
332  $this->peer_file = (bool)$a_val;
333  }
334 
341  {
342  return $this->peer_file;
343  }
344 
350  function setPeerReviewPersonalized($a_val)
351  {
352  $this->peer_personal = (bool)$a_val;
353  }
354 
361  {
362  return $this->peer_personal;
363  }
364 
370  function setFeedbackFile($a_value)
371  {
372  $this->feedback_file = (string)$a_value;
373  }
374 
380  function getFeedbackFile()
381  {
382  return (string)$this->feedback_file;
383  }
384 
390  function setFeedbackCron($a_value)
391  {
392  $this->feedback_cron = (string)$a_value;
393  }
394 
400  function hasFeedbackCron()
401  {
402  return (bool)$this->feedback_cron;
403  }
404 
410  function setFeedbackDate($a_value)
411  {
412  $this->feedback_date = (int)$a_value;
413  }
414 
420  function getFeedbackDate()
421  {
422  return (int)$this->feedback_date;
423  }
424 
428  function read()
429  {
430  global $ilDB;
431 
432  $set = $ilDB->query("SELECT * FROM exc_assignment ".
433  " WHERE id = ".$ilDB->quote($this->getId(), "integer")
434  );
435  while ($rec = $ilDB->fetchAssoc($set))
436  {
437  $this->setExerciseId($rec["exc_id"]);
438  $this->setDeadline($rec["time_stamp"]);
439  $this->setInstruction($rec["instruction"]);
440  $this->setTitle($rec["title"]);
441  $this->setStartTime($rec["start_time"]);
442  $this->setOrderNr($rec["order_nr"]);
443  $this->setMandatory($rec["mandatory"]);
444  $this->setType($rec["type"]);
445  $this->setPeerReview($rec["peer"]);
446  $this->setPeerReviewMin($rec["peer_min"]);
447  $this->setPeerReviewDeadline($rec["peer_dl"]);
448  $this->setPeerReviewFileUpload($rec["peer_file"]);
449  $this->setPeerReviewPersonalized($rec["peer_prsl"]);
450  $this->setFeedbackFile($rec["fb_file"]);
451  $this->setFeedbackDate($rec["fb_date"]);
452  $this->setFeedbackCron($rec["fb_cron"]);
453  }
454  }
455 
459  function save()
460  {
461  global $ilDB;
462 
463  if ($this->getOrderNr() == 0)
464  {
465  $this->setOrderNr(
467  + 10);
468  }
469 
470  $next_id = $ilDB->nextId("exc_assignment");
471  $ilDB->insert("exc_assignment", array(
472  "id" => array("integer", $next_id),
473  "exc_id" => array("integer", $this->getExerciseId()),
474  "time_stamp" => array("integer", $this->getDeadline()),
475  "instruction" => array("clob", $this->getInstruction()),
476  "title" => array("text", $this->getTitle()),
477  "start_time" => array("integer", $this->getStartTime()),
478  "order_nr" => array("integer", $this->getOrderNr()),
479  "mandatory" => array("integer", $this->getMandatory()),
480  "type" => array("integer", $this->getType()),
481  "peer" => array("integer", $this->getPeerReview()),
482  "peer_min" => array("integer", $this->getPeerReviewMin()),
483  "peer_dl" => array("integer", $this->getPeerReviewDeadline()),
484  "peer_file" => array("integer", $this->hasPeerReviewFileUpload()),
485  "peer_prsl" => array("integer", $this->hasPeerReviewPersonalized()),
486  "fb_file" => array("text", $this->getFeedbackFile()),
487  "fb_date" => array("integer", $this->getFeedbackDate()),
488  "fb_cron" => array("integer", $this->hasFeedbackCron()))
489  );
490  $this->setId($next_id);
491  $exc = new ilObjExercise($this->getExerciseId(), false);
492  $exc->updateAllUsersStatus();
494 
495  $this->handleCalendarEntries("create");
496  }
497 
501  function update()
502  {
503  global $ilDB;
504 
505  $ilDB->update("exc_assignment",
506  array(
507  "exc_id" => array("integer", $this->getExerciseId()),
508  "time_stamp" => array("integer", $this->getDeadline()),
509  "instruction" => array("clob", $this->getInstruction()),
510  "title" => array("text", $this->getTitle()),
511  "start_time" => array("integer", $this->getStartTime()),
512  "order_nr" => array("integer", $this->getOrderNr()),
513  "mandatory" => array("integer", $this->getMandatory()),
514  "type" => array("integer", $this->getType()),
515  "peer" => array("integer", $this->getPeerReview()),
516  "peer_min" => array("integer", $this->getPeerReviewMin()),
517  "peer_dl" => array("integer", $this->getPeerReviewDeadline()),
518  "peer_file" => array("integer", $this->hasPeerReviewFileUpload()),
519  "peer_prsl" => array("integer", $this->hasPeerReviewPersonalized()),
520  "fb_file" => array("text", $this->getFeedbackFile()),
521  "fb_date" => array("integer", $this->getFeedbackDate()),
522  "fb_cron" => array("integer", $this->hasFeedbackCron())
523  ),
524  array(
525  "id" => array("integer", $this->getId()),
526  ));
527  $exc = new ilObjExercise($this->getExerciseId(), false);
528  $exc->updateAllUsersStatus();
529 
530  $this->handleCalendarEntries("update");
531  }
532 
536  function delete()
537  {
538  global $ilDB;
539 
540  $this->deleteFeedbackFile();
541 
542  $ilDB->manipulate("DELETE FROM exc_assignment WHERE ".
543  " id = ".$ilDB->quote($this->getId(), "integer")
544  );
545  $exc = new ilObjExercise($this->getExerciseId(), false);
546  $exc->updateAllUsersStatus();
547 
548  $this->handleCalendarEntries("delete");
549  }
550 
552  {
553  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
554  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
555  $path = $storage->getGlobalFeedbackPath();
557  }
558 
559  function handleFeedbackFileUpload(array $a_file)
560  {
561  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
562  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
563  $path = $storage->getGlobalFeedbackPath();
564  ilUtil::delDir($path, true);
565  if(@move_uploaded_file($a_file["tmp_name"], $path."/".$a_file["name"]))
566  {
567  $this->setFeedbackFile($a_file["name"]);
568  return true;
569  }
570  return false;
571  }
572 
574  {
575  $file = $this->getFeedbackFile();
576  if($file)
577  {
578  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
579  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
580  $path = $storage->getGlobalFeedbackPath();
581  return $path."/".$file;
582  }
583  }
584 
588  static function getAssignmentDataOfExercise($a_exc_id)
589  {
590  global $ilDB;
591 
592  $set = $ilDB->query("SELECT * FROM exc_assignment ".
593  " WHERE exc_id = ".$ilDB->quote($a_exc_id, "integer").
594  " ORDER BY order_nr ASC");
595  $data = array();
596 
597  $order_val = 10;
598  while ($rec = $ilDB->fetchAssoc($set))
599  {
600 
601  $data[] = array(
602  "id" => $rec["id"],
603  "exc_id" => $rec["exc_id"],
604  "deadline" => $rec["time_stamp"],
605  "instruction" => $rec["instruction"],
606  "title" => $rec["title"],
607  "start_time" => $rec["start_time"],
608  "order_val" => $order_val,
609  "mandatory" => $rec["mandatory"],
610  "type" => $rec["type"],
611  "peer" => $rec["peer"],
612  "peer_min" => $rec["peer_min"],
613  "peer_dl" => $rec["peer_dl"],
614  "peer_file" => $rec["peer_file"],
615  "peer_prsl" => $rec["peer_prsl"],
616  "fb_file" => $rec["fb_file"],
617  "fb_date" => $rec["fb_date"],
618  "fb_cron" => $rec["fb_cron"],
619  );
620  $order_val += 10;
621  }
622  return $data;
623  }
624 
631  function cloneAssignmentsOfExercise($a_old_exc_id, $a_new_exc_id)
632  {
633  $ass_data = ilExAssignment::getAssignmentDataOfExercise($a_old_exc_id);
634  foreach ($ass_data as $d)
635  {
636  // clone assignment
637  $new_ass = new ilExAssignment();
638  $new_ass->setExerciseId($a_new_exc_id);
639  $new_ass->setTitle($d["title"]);
640  $new_ass->setDeadline($d["deadline"]);
641  $new_ass->setInstruction($d["instruction"]);
642  $new_ass->setMandatory($d["mandatory"]);
643  $new_ass->setOrderNr($d["order_val"]);
644  $new_ass->setStartTime($d["start_time"]);
645  $new_ass->setType($d["type"]);
646  $new_ass->setPeerReview($d["peer"]);
647  $new_ass->setPeerReviewMin($d["peer_min"]);
648  $new_ass->setPeerReviewDeadline($d["peer_dl"]);
649  $new_ass->setPeerReviewFileUpload($d["peer_file"]);
650  $new_ass->setPeerReviewPersonalized($d["peer_prsl"]);
651  $new_ass->setFeedbackFile($d["fb_file"]);
652  $new_ass->setFeedbackDate($d["fb_date"]);
653  $new_ass->setFeedbackCron($d["fb_cron"]);
654  $new_ass->save();
655 
656  // clone assignment files
657  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
658  $old_storage = new ilFSStorageExercise($a_old_exc_id, (int) $d["id"]);
659  $new_storage = new ilFSStorageExercise($a_new_exc_id, (int) $new_ass->getId());
660  $new_storage->create();
661 
662  if (is_dir($old_storage->getPath()))
663  {
664  ilUtil::rCopy($old_storage->getPath(), $new_storage->getPath());
665  }
666  }
667  }
668 
672  static function getFiles($a_exc_id, $a_ass_id)
673  {
674  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
675  $storage = new ilFSStorageExercise($a_exc_id, $a_ass_id);
676  return $storage->getFiles();
677  }
678 
682  static function lookupMaxOrderNrForEx($a_exc_id)
683  {
684  global $ilDB;
685 
686  $set = $ilDB->query("SELECT MAX(order_nr) mnr FROM exc_assignment ".
687  " WHERE exc_id = ".$ilDB->quote($a_exc_id, "integer")
688  );
689  while ($rec = $ilDB->fetchAssoc($set))
690  {
691  return (int) $rec["mnr"];
692  }
693  return 0;
694  }
695 
701  public static function lookupAssignmentOnline($a_ass_id)
702  {
703  global $ilDB;
704 
705  $query = "SELECT id FROM exc_assignment ".
706  "WHERE start_time <= ".$ilDB->quote(time(),'integer').' '.
707  "AND time_stamp >= ".$ilDB->quote(time(),'integer').' '.
708  "AND id = ".$ilDB->quote($a_ass_id,'integer');
709  $res = $ilDB->query($query);
710 
711  return $res->numRows() ? true : false;
712  }
713 
714 
718  private static function lookup($a_id, $a_field)
719  {
720  global $ilDB;
721 
722  $set = $ilDB->query("SELECT ".$a_field." FROM exc_assignment ".
723  " WHERE id = ".$ilDB->quote($a_id, "integer")
724  );
725 
726  $rec = $ilDB->fetchAssoc($set);
727 
728  return $rec[$a_field];
729  }
730 
734  static function lookupTitle($a_id)
735  {
736  return ilExAssignment::lookup($a_id, "title");
737  }
738 
742  static function lookupType($a_id)
743  {
744  return ilExAssignment::lookup($a_id, "type");
745  }
746 
750  function saveAssOrderOfExercise($a_ex_id, $a_order)
751  {
752  global $ilDB;
753 
754  $result_order = array();
755  asort($a_order);
756  $nr = 10;
757  foreach ($a_order as $k => $v)
758  {
759  // the check for exc_id is for security reasons. ass ids are unique.
760  $ilDB->manipulate($t = "UPDATE exc_assignment SET ".
761  " order_nr = ".$ilDB->quote($nr, "integer").
762  " WHERE id = ".$ilDB->quote((int) $k, "integer").
763  " AND exc_id = ".$ilDB->quote((int) $a_ex_id, "integer")
764  );
765  $nr+=10;
766  }
767  }
768 
772  function orderAssByDeadline($a_ex_id)
773  {
774  global $ilDB;
775 
776  $set = $ilDB->query("SELECT id FROM exc_assignment ".
777  " WHERE exc_id = ".$ilDB->quote($a_ex_id, "integer").
778  " ORDER BY time_stamp ASC"
779  );
780  $nr = 10;
781  while ($rec = $ilDB->fetchAssoc($set))
782  {
783  $ilDB->manipulate("UPDATE exc_assignment SET ".
784  " order_nr = ".$ilDB->quote($nr, "integer").
785  " WHERE id = ".$ilDB->quote($rec["id"], "integer")
786  );
787  $nr += 10;
788  }
789  }
790 
794  function countMandatory($a_ex_id)
795  {
796  global $ilDB;
797 
798  $set = $ilDB->query("SELECT count(*) cntm FROM exc_assignment ".
799  " WHERE exc_id = ".$ilDB->quote($a_ex_id, "integer").
800  " AND mandatory = ".$ilDB->quote(1, "integer")
801  );
802  $rec = $ilDB->fetchAssoc($set);
803  return $rec["cntm"];
804  }
805 
809 
813  private function lookupAssMemberField($a_ass_id, $a_user_id, $a_field)
814  {
815  global $ilDB;
816 
817  $set = $ilDB->query("SELECT ".$a_field." FROM exc_mem_ass_status ".
818  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
819  " AND usr_id = ".$ilDB->quote($a_user_id, "integer")
820  );
821  $rec = $ilDB->fetchAssoc($set);
822 
823  return $rec[$a_field];
824  }
825 
829  private function updateAssMemberField($a_ass_id, $a_user_id, $a_field, $a_value, $a_type)
830  {
831  global $ilDB;
832 
833  $ilDB->manipulate("UPDATE exc_mem_ass_status SET ".
834  " ".$a_field." = ".$ilDB->quote($a_value, $a_type).
835  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
836  " AND usr_id = ".$ilDB->quote($a_user_id, "integer")
837  );
838  }
839 
840 
841 /* function setStatus($a_status)
842  {
843  if(is_array($a_status))
844  {
845  $this->status = $a_status;
846  return true;
847  }
848  }
849  function getStatus()
850  {
851  return $this->status ? $this->status : array();
852  }*/
853 
857  function lookupCommentForUser($a_ass_id, $a_user_id)
858  {
859  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "u_comment");
860  }
861 
865  function updateCommentForUser($a_ass_id, $a_user_id, $a_value)
866  {
867  ilExAssignment::updateAssMemberField($a_ass_id, $a_user_id,
868  "u_comment", $a_value, "text");
869  }
870 
874  function lookupMarkOfUser($a_ass_id, $a_user_id)
875  {
876  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "mark");
877  }
878 
882  function updateMarkOfUser($a_ass_id, $a_user_id, $a_value)
883  {
884  ilExAssignment::updateAssMemberField($a_ass_id, $a_user_id,
885  "mark", $a_value, "text");
886  }
887 
891  function lookupStatusOfUser($a_ass_id, $a_user_id)
892  {
893  $stat = ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "status");
894  if ($stat == "")
895  {
896  $stat = "notgraded";
897  }
898  return $stat;
899  }
900 
904  function updateStatusOfUser($a_ass_id, $a_user_id, $a_status)
905  {
906  global $ilDB;
907 
908  $ilDB->manipulateF("UPDATE exc_mem_ass_status ".
909  "SET status = %s, status_time= %s ".
910  " WHERE ass_id = %s AND usr_id = %s AND status <> %s ",
911  array("text", "timestamp", "integer", "integer", "text"),
912  array($a_status, ilUtil::now(), $a_ass_id, $a_user_id, $a_status));
913 
914  $ass = new ilExAssignment($a_ass_id);
915  $exc = new ilObjExercise($ass->getExerciseId(), false);
916  $exc->updateUserStatus($a_user_id);
917  }
918 
922  function updateStatusTimeOfUser($a_ass_id, $a_user_id)
923  {
924  // #13741 - is only used for mark
925  ilExAssignment::updateAssMemberField($a_ass_id, $a_user_id,
926  "status_time", ilUtil::now(), "timestamp");
927  }
928 
929 
930  /*function setStatusSent($a_status)
931  {
932  if(is_array($a_status))
933  {
934  $this->status_sent = $a_status;
935  return true;
936  }
937  }
938  function getStatusSent()
939  {
940  return $this->status_sent ? $this->status_sent : array(0 => 0);
941  }*/
942 
946  function lookupStatusSentOfUser($a_ass_id, $a_user_id)
947  {
948  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "sent");
949  }
950 
954  function updateStatusSentForUser($a_ass_id, $a_user_id, $a_status)
955  {
956  global $ilDB;
957 
958  // #13741
959  $ilDB->manipulateF("UPDATE exc_mem_ass_status ".
960  "SET sent = %s, sent_time = %s ".
961  " WHERE ass_id = %s AND usr_id = %s ",
962  array("integer", "timestamp", "integer", "integer"),
963  array((int) $a_status, ($a_status ? ilUtil::now() : null),
964  $a_ass_id, $a_user_id));
965  }
966 
967  /*function getStatusReturned()
968  {
969  return $this->status_returned ? $this->status_returned : array(0 => 0);
970  }
971  function setStatusReturned($a_status)
972  {
973  if(is_array($a_status))
974  {
975  $this->status_returned = $a_status;
976  return true;
977  }
978  return false;
979  }*/
980 
984  function lookupStatusReturnedOfUser($a_ass_id, $a_user_id)
985  {
986  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "returned");
987  }
988 
992  function updateStatusReturnedForUser($a_ass_id, $a_user_id, $a_status)
993  {
994  global $ilDB;
995 
996  // first upload => notification on submission?
997  if($a_status &&
998  !self::lookupStatusReturnedOfUser($a_ass_id, $a_user_id))
999  {
1000  $set = $ilDB->query("SELECT fb_cron, fb_date, fb_file".
1001  " FROM exc_assignment".
1002  " WHERE id = ".$ilDB->quote($a_ass_id, "integer"));
1003  $row = $ilDB->fetchAssoc($set);
1004  if($row["fb_cron"] &&
1005  $row["fb_file"] &&
1006  $row["fb_date"] == self::FEEDBACK_DATE_SUBMISSION)
1007  {
1008  ilExAssignment::sendFeedbackNotifications($a_ass_id, $a_user_id);
1009  }
1010  }
1011 
1012  // #13741
1013  $ilDB->manipulateF("UPDATE exc_mem_ass_status".
1014  " SET returned = %s".
1015  " WHERE ass_id = %s AND usr_id = %s",
1016  array("integer", "integer", "integer"),
1017  array((int) $a_status, $a_ass_id, $a_user_id));
1018  }
1019 
1020 /* // feedback functions
1021  function setStatusFeedback($a_status)
1022  {
1023  if(is_array($a_status))
1024  {
1025  $this->status_feedback = $a_status;
1026  return true;
1027  }
1028  }
1029  function getStatusFeedback()
1030  {
1031  return $this->status_feedback ? $this->status_feedback : array(0 => 0);
1032  }*/
1033 
1037  function lookupStatusFeedbackOfUser($a_ass_id, $a_user_id)
1038  {
1039  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "feedback");
1040  }
1041 
1045  function updateStatusFeedbackForUser($a_ass_id, $a_user_id, $a_status)
1046  {
1047  global $ilDB;
1048 
1049  // #13741
1050  $ilDB->manipulateF("UPDATE exc_mem_ass_status ".
1051  "SET feedback = %s, feedback_time = %s ".
1052  " WHERE ass_id = %s AND usr_id = %s",
1053  array("integer", "timestamp", "integer", "integer"),
1054  array((int) $a_status, ($a_status ? ilUtil::now() : null),
1055  $a_ass_id, $a_user_id));
1056  }
1057 
1061  static function lookupSentTimeOfUser($a_ass_id, $a_user_id)
1062  {
1064  ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "sent_time"));
1065  }
1066 
1070  static function lookupFeedbackTimeOfUser($a_ass_id, $a_user_id)
1071  {
1073  ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "feedback_time"));
1074  }
1075 
1079  static function lookupStatusTimeOfUser($a_ass_id, $a_user_id)
1080  {
1082  ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "status_time"));
1083  }
1084 
1085  /*function getNotice()
1086  {
1087  return $this->notice ? $this->notice : array(0 => 0);
1088  }
1089 
1090  function setNotice($a_notice)
1091  {
1092  if(is_array($a_notice))
1093  {
1094  $this->notice = $a_notice;
1095  return true;
1096  }
1097  return false;
1098  }*/
1099 
1103  function lookupNoticeOfUser($a_ass_id, $a_user_id)
1104  {
1105  return ilExAssignment::lookupAssMemberField($a_ass_id, $a_user_id, "notice");
1106  }
1107 
1111  function hasReturned($a_ass_id, $a_user_id)
1112  {
1113  global $ilDB;
1114 
1115  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1116  if(!$user_ids)
1117  {
1118  $user_ids = array($a_user_id);
1119  }
1120 
1121  $result = $ilDB->query("SELECT returned_id FROM exc_returned".
1122  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
1123  " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
1124  return $ilDB->numRows($result);
1125  }
1126 
1130  function getAllDeliveredFiles($a_exc_id, $a_ass_id)
1131  {
1132  global $ilDB;
1133 
1134  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1135  $fs = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1136 
1137  $query = "SELECT * FROM exc_returned WHERE ass_id = ".
1138  $ilDB->quote($a_ass_id, "integer");
1139 
1140  $res = $ilDB->query($query);
1141  while($row = $ilDB->fetchAssoc($res))
1142  {
1143  $row["timestamp"] = $row["ts"];
1144  $row["filename"] = $fs->getAbsoluteSubmissionPath().
1145  "/".$row["user_id"]."/".basename($row["filename"]);
1146  $delivered[] = $row;
1147  }
1148 
1149  //$delivered = ilObjExercise::_fixFilenameArray($delivered);
1150 
1151  return $delivered ? $delivered : array();
1152  }
1153 
1157  function getDeliveredFiles($a_exc_id, $a_ass_id, $a_user_id, $a_filter_empty_filename = false)
1158  {
1159  global $ilDB;
1160 
1161  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1162  if(!$user_ids)
1163  {
1164  $user_ids = array($a_user_id);
1165  }
1166 
1167  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1168  $fs = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1169 
1170  $result = $ilDB->query("SELECT * FROM exc_returned".
1171  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
1172  " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
1173 
1174  $delivered_files = array();
1175  if ($ilDB->numRows($result))
1176  {
1177  while ($row = $ilDB->fetchAssoc($result))
1178  {
1179  if($a_filter_empty_filename && !$row["filename"])
1180  {
1181  continue;
1182  }
1183  $row["owner_id"] = $row["user_id"];
1184  $row["timestamp"] = $row["ts"];
1185  $row["timestamp14"] = substr($row["ts"], 0, 4).
1186  substr($row["ts"], 5, 2).substr($row["ts"], 8, 2).
1187  substr($row["ts"], 11, 2).substr($row["ts"], 14, 2).
1188  substr($row["ts"], 17, 2);
1189  $row["filename"] = $fs->getAbsoluteSubmissionPath().
1190  "/".$row["user_id"]."/".basename($row["filename"]);
1191  array_push($delivered_files, $row);
1192  }
1193  }
1194 
1195  //$delivered_files = ilObjExercise::_fixFilenameArray($delivered_files);
1196  return $delivered_files;
1197  }
1198 
1202  function deleteDeliveredFiles($a_exc_id, $a_ass_id, $file_id_array, $a_user_id)
1203  {
1204  global $ilDB;
1205 
1206  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1207  $fs = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1208 
1209  if (count($file_id_array))
1210  {
1211  $team_id = self::getTeamIdByAssignment($a_ass_id, $a_user_id);
1212  if($team_id)
1213  {
1214  // #11733
1215  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1216  if(!$user_ids)
1217  {
1218  return;
1219  }
1220  }
1221  else
1222  {
1223  $user_ids = array($a_user_id);
1224  }
1225 
1226  $result = $ilDB->query("SELECT * FROM exc_returned".
1227  " WHERE ".$ilDB->in("returned_id", $file_id_array, false, "integer").
1228  " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
1229 
1230  if ($ilDB->numRows($result))
1231  {
1232  $result_array = array();
1233  while ($row = $ilDB->fetchAssoc($result))
1234  {
1235  $row["timestamp"] = $row["ts"];
1236  array_push($result_array, $row);
1237  }
1238 
1239  // delete the entries in the database
1240  $ilDB->manipulate("DELETE FROM exc_returned".
1241  " WHERE ".$ilDB->in("returned_id", $file_id_array, false, "integer").
1242  " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
1243 
1244  // delete the files
1245  foreach ($result_array as $key => $value)
1246  {
1247  if($value["filename"])
1248  {
1249  if($team_id)
1250  {
1251  ilExAssignment::writeTeamLog($team_id,
1252  ilExAssignment::TEAM_LOG_REMOVE_FILE, $value["filetitle"]);
1253  }
1254 
1255  $filename = $fs->getAbsoluteSubmissionPath().
1256  "/".$value["user_id"]."/".basename($value["filename"]);
1257  unlink($filename);
1258  }
1259  }
1260  }
1261  }
1262  }
1263 
1270  static function deleteAllDeliveredFilesOfUser($a_exc_id, $a_user_id)
1271  {
1272  global $ilDB;
1273 
1274  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1275 
1276  $delete_ids = array();
1277 
1278  // get the files and...
1279  $set = $ilDB->query("SELECT * FROM exc_returned ".
1280  " WHERE obj_id = ".$ilDB->quote($a_exc_id, "integer").
1281  " AND user_id = ".$ilDB->quote($a_user_id, "integer")
1282  );
1283  while ($rec = $ilDB->fetchAssoc($set))
1284  {
1285  $ass = new self($rec["ass_id"]);
1286  if($ass->getType() == self::TYPE_UPLOAD_TEAM)
1287  {
1288  // switch upload to other team member
1289  $team = self::getTeamMembersByAssignmentId($ass->getId(), $a_user_id);
1290  if(sizeof($team) > 1)
1291  {
1292  $new_owner = array_pop($team);
1293  while($new_owner == $a_user_id && sizeof($team))
1294  {
1295  $new_owner = array_pop($team);
1296  }
1297 
1298  $ilDB->manipulate("UPDATE exc_returned".
1299  " SET user_id = ".$ilDB->quote($new_owner, "integer").
1300  " WHERE returned_id = ".$ilDB->quote($rec["returned_id"], "integer")
1301  );
1302 
1303  // no need to delete
1304  continue;
1305  }
1306  }
1307 
1308  $delete_ids[] = $rec["returned_id"];
1309 
1310  $fs = new ilFSStorageExercise($a_exc_id, $rec["ass_id"]);
1311 
1312  // ...delete files
1313  $filename = $fs->getAbsoluteSubmissionPath().
1314  "/".$a_user_id."/".basename($rec["filename"]);
1315  if (is_file($filename))
1316  {
1317  unlink($filename);
1318  }
1319  }
1320 
1321  // delete exc_returned records
1322  if($delete_ids)
1323  {
1324  $ilDB->manipulate("DELETE FROM exc_returned".
1325  " WHERE ".$ilDB->in("returned_id", $delete_ids, "", "integer"));
1326  }
1327 
1328  // delete il_exc_team records
1329  $ass_ids = array();
1330  foreach(self::getAssignmentDataOfExercise($a_exc_id) as $item)
1331  {
1332  self::updateStatusOfUser($item["id"], $a_user_id, "notgraded"); // #14900
1333 
1334  $ass_ids[] = $item["id"];
1335  }
1336  if($ass_ids)
1337  {
1338  $ilDB->manipulate($d = "DELETE FROM il_exc_team WHERE ".
1339  "user_id = ".$ilDB->quote($a_user_id, "integer").
1340  " AND ".$ilDB->in("ass_id", $ass_ids, "", "integer")
1341  );
1342  }
1343  }
1344 
1345 
1349  function deliverReturnedFiles($a_exc_id, $a_ass_id, $a_user_id, $a_only_new = false, $a_peer_review_mask_filename = false)
1350  {
1351  global $ilUser, $ilDB;
1352 
1353  // #11000 / #11785
1354  $is_team = true;
1355  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1356  if(!$user_ids)
1357  {
1358  $is_team = false;
1359  $user_ids = array($a_user_id);
1360  }
1361 
1362  // get last download time
1363  $and_str = "";
1364  if ($a_only_new)
1365  {
1366  $q = "SELECT download_time FROM exc_usr_tutor WHERE ".
1367  " ass_id = ".$ilDB->quote($a_ass_id, "integer")." AND ".
1368  $ilDB->in("usr_id", $user_ids, "", "integer")." AND ".
1369  " tutor_id = ".$ilDB->quote($ilUser->getId(), "integer");
1370  $lu_set = $ilDB->query($q);
1371  if ($lu_rec = $ilDB->fetchAssoc($lu_set))
1372  {
1373  if ($lu_rec["download_time"] > 0)
1374  {
1375  $and_str = " AND ts > ".$ilDB->quote($lu_rec["download_time"], "timestamp");
1376  }
1377  }
1378  }
1379 
1380  foreach($user_ids as $user_id)
1381  {
1382  ilExAssignment::updateTutorDownloadTime($a_exc_id, $a_ass_id, $user_id);
1383  }
1384 
1385  if($a_peer_review_mask_filename)
1386  {
1387  // process peer review sequence id
1388  $peer_id = null;
1389  foreach($this->ass->getPeerReviewsByGiver($ilUser->getId()) as $idx => $item)
1390  {
1391  if($item["peer_id"] == $a_user_id)
1392  {
1393  $peer_id = $idx+1;
1394  break;
1395  }
1396  }
1397  }
1398 
1399  $query = "SELECT * FROM exc_returned".
1400  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
1401  " AND ".$ilDB->in("user_id", $user_ids, "", "integer").
1402  $and_str;
1403 
1404  $result = $ilDB->query($query);
1405  $count = $ilDB->numRows($result);
1406  if ($count == 1)
1407  {
1408  $row = $ilDB->fetchAssoc($result);
1409 
1410  switch(self::lookupType($a_ass_id))
1411  {
1412  case self::TYPE_BLOG:
1413  case self::TYPE_PORTFOLIO:
1414  $row["filetitle"] = ilObjUser::_lookupName($row["user_id"]);
1415  $row["filetitle"] = ilObject::_lookupTitle($a_exc_id)." - ".
1416  self::lookupTitle($a_ass_id)." - ".
1417  $row["filetitle"]["firstname"]." ".
1418  $row["filetitle"]["lastname"]." (".
1419  $row["filetitle"]["login"].").zip";
1420  break;
1421 
1422  default:
1423  break;
1424  }
1425 
1426  if($a_peer_review_mask_filename)
1427  {
1428  $suffix = array_pop(explode(".", $row["filetitle"]));
1429  $row["filetitle"] = self::lookupTitle($a_ass_id)."_peer".$peer_id.".".$suffix;
1430  }
1431 
1432  ilExAssignment::downloadSingleFile($a_exc_id, $a_ass_id, $row["user_id"],
1433  $row["filename"], $row["filetitle"]);
1434  }
1435  else if ($count > 0)
1436  {
1437  $array_files = array();
1438  $seq = 0;
1439  while ($row = $ilDB->fetchAssoc($result))
1440  {
1441  $src = basename($row["filename"]);
1442  if($a_peer_review_mask_filename)
1443  {
1444  $suffix = array_pop(explode(".", $src));
1445  $tgt = self::lookupTitle($a_ass_id)."_peer".$peer_id.
1446  "_".(++$seq).".".$suffix;
1447 
1448  $array_files[$row["user_id"]][] = array($src, $tgt);
1449  }
1450  else
1451  {
1452  $array_files[$row["user_id"]][] = $src;
1453  }
1454  }
1455  ilExAssignment::downloadMultipleFiles($a_exc_id, $a_ass_id, $array_files,
1456  ($is_team ? null : $a_user_id), $is_team);
1457  }
1458  else
1459  {
1460  return false;
1461  }
1462 
1463  return true;
1464  }
1465 
1466  // Update the timestamp of the last download of current user (=tutor)
1470  function updateTutorDownloadTime($a_exc_id, $a_ass_id, $a_user_id)
1471  {
1472  global $ilUser, $ilDB;
1473 
1474  $ilDB->manipulateF("DELETE FROM exc_usr_tutor ".
1475  "WHERE ass_id = %s AND usr_id = %s AND tutor_id = %s",
1476  array("integer", "integer", "integer"),
1477  array($a_ass_id, $a_user_id, $ilUser->getId()));
1478 
1479  $ilDB->manipulateF("INSERT INTO exc_usr_tutor (ass_id, obj_id, usr_id, tutor_id, download_time) VALUES ".
1480  "(%s, %s, %s, %s, %s)",
1481  array("integer", "integer", "integer", "integer", "timestamp"),
1482  array($a_ass_id, $a_exc_id, $a_user_id, $ilUser->getId(), ilUtil::now()));
1483  }
1484 
1488  function downloadSelectedFiles($a_exc_id, $a_ass_id, $a_user_id, $array_file_id)
1489  {
1490  global $ilDB;
1491 
1492  if (count($array_file_id))
1493  {
1494  // #11785
1495  $is_team = true;
1496  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1497  if(!$user_ids)
1498  {
1499  $is_team = false;
1500  $user_ids = array($a_user_id);
1501  }
1502 
1503  $result = $ilDB->query("SELECT * FROM exc_returned WHERE ".
1504  $ilDB->in("returned_id", $array_file_id, false, "integer").
1505  " AND ".$ilDB->in("user_id", $user_ids, "", "integer"));
1506  if ($ilDB->numRows($result))
1507  {
1508  $array_found = array();
1509  while ($row = $ilDB->fetchAssoc($result))
1510  {
1511  $row["timestamp"] = $row["ts"];
1512  array_push($array_found, $row);
1513  }
1514  if (count($array_found) == 1)
1515  {
1516  // blog/portfolio submission
1517  if(is_numeric($array_found[0]["filetitle"]))
1518  {
1519  $ass = new ilExAssignment($array_found[0]["ass_id"]);
1520  if($ass->getType() == ilExAssignment::TYPE_BLOG ||
1521  $ass->getType() == ilExAssignment::TYPE_PORTFOLIO)
1522  {
1523  $user_data = ilObjUser::_lookupName($array_found[0]["user_id"]);
1524  $array_found[0]["filetitle"] = ilObject::_lookupTitle($array_found[0]["obj_id"])." - ".
1525  $ass->getTitle()." - ".
1526  $user_data["firstname"]." ".
1527  $user_data["lastname"]." (".
1528  $user_data["login"].").zip";
1529  }
1530  }
1531 
1532  ilExAssignment::downloadSingleFile($a_exc_id, $a_ass_id, $array_found[0]["user_id"],
1533  $array_found[0]["filename"], $array_found[0]["filetitle"]);
1534  }
1535  else
1536  {
1537  $filenames = array();
1538  foreach ($array_found as $value)
1539  {
1540  $filenames[$value["user_id"]][] = basename($value["filename"]);
1541  }
1542  ilExAssignment::downloadMultipleFiles($a_exc_id, $a_ass_id,
1543  $filenames, ($is_team ? null : $a_user_id), $is_team);
1544  }
1545  }
1546  }
1547  }
1548 
1552  function downloadSingleFile($a_exc_id, $a_ass_id, $a_user_id, $filename, $filetitle)
1553  {
1554  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1555  $fs = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1556 
1557  $filename = $fs->getAbsoluteSubmissionPath().
1558  "/".$a_user_id."/".basename($filename);
1559 
1560  require_once "./Services/Utilities/classes/class.ilUtil.php";
1561  ilUtil::deliverFile($filename, $filetitle);
1562  }
1563 
1567 // @todo: check whether files of multiple users are downloaded this way
1568  function downloadMultipleFiles($a_exc_id, $a_ass_id, $array_filenames,
1569  $a_user_id, $a_multi_user = false)
1570  {
1571  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1572  $fs = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1573 
1574  require_once "./Services/Utilities/classes/class.ilUtil.php";
1575  $cdir = getcwd();
1576 
1577  $zip = PATH_TO_ZIP;
1578  $tmpdir = ilUtil::ilTempnam();
1579  $tmpfile = ilUtil::ilTempnam();
1580  $tmpzipfile = $tmpfile . ".zip";
1581 
1582  ilUtil::makeDir($tmpdir);
1583  chdir($tmpdir);
1584 
1585  $assTitle = ilExAssignment::lookupTitle($a_ass_id);
1586  $deliverFilename = str_replace(" ", "_", $assTitle);
1587  if ($a_user_id > 0 && !$a_multi_user)
1588  {
1589  $userName = ilObjUser::_lookupName($a_user_id);
1590  $deliverFilename .= "_".$userName["lastname"]."_".$userName["firstname"];
1591  }
1592  else
1593  {
1594  $deliverFilename .= "_files";
1595  }
1596  $orgDeliverFilename = trim($deliverFilename);
1597  $deliverFilename = ilUtil::getASCIIFilename($orgDeliverFilename);
1598  ilUtil::makeDir($tmpdir."/".$deliverFilename);
1599  chdir($tmpdir."/".$deliverFilename);
1600 
1601  //copy all files to a temporary directory and remove them afterwards
1602  $parsed_files = $duplicates = array();
1603  foreach ($array_filenames as $user_id => $files)
1604  {
1605  $pathname = $fs->getAbsoluteSubmissionPath()."/".$user_id;
1606 
1607  foreach($files as $filename)
1608  {
1609  // peer review masked filenames, see deliverReturnedFiles()
1610  if(is_array($filename))
1611  {
1612  $newFilename = $filename[1];
1613  $filename = $filename[0];
1614  }
1615  else
1616  {
1617  // remove timestamp
1618  $newFilename = trim($filename);
1619  $pos = strpos($newFilename , "_");
1620  if ($pos !== false)
1621  {
1622  $newFilename = substr($newFilename, $pos + 1);
1623  }
1624  // #11070
1625  $chkName = strtolower($newFilename);
1626  if(array_key_exists($chkName, $duplicates))
1627  {
1628  $suffix = strrpos($newFilename, ".");
1629  $newFilename = substr($newFilename, 0, $suffix).
1630  " (".(++$duplicates[$chkName]).")".
1631  substr($newFilename, $suffix);
1632  }
1633  else
1634  {
1635  $duplicates[$chkName] = 1;
1636  }
1637  }
1638  $newFilename = $tmpdir.DIRECTORY_SEPARATOR.$deliverFilename.DIRECTORY_SEPARATOR.$newFilename;
1639  // copy to temporal directory
1640  $oldFilename = $pathname.DIRECTORY_SEPARATOR.$filename;
1641  if (!copy ($oldFilename, $newFilename))
1642  {
1643  echo 'Could not copy '.$oldFilename.' to '.$newFilename;
1644  }
1645  touch($newFilename, filectime($oldFilename));
1646  $parsed_files[] = ilUtil::escapeShellArg($deliverFilename.DIRECTORY_SEPARATOR.basename($newFilename));
1647  }
1648  }
1649 
1650  chdir($tmpdir);
1651  $zipcmd = $zip." ".ilUtil::escapeShellArg($tmpzipfile)." ".join($parsed_files, " ");
1652 
1653  exec($zipcmd);
1654  ilUtil::delDir($tmpdir);
1655 
1656  chdir($cdir);
1657  ilUtil::deliverFile($tmpzipfile, $orgDeliverFilename.".zip", "", false, true);
1658  exit;
1659  }
1660 
1666  function downloadAllDeliveredFiles($a_exc_id, $a_ass_id, $members)
1667  {
1668  global $lng, $ilObjDataCache, $ilias;
1669 
1670  include_once "./Services/Utilities/classes/class.ilUtil.php";
1671  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
1672 
1673  $storage = new ilFSStorageExercise($a_exc_id, $a_ass_id);
1674  $storage->create();
1675 
1676  ksort($members);
1677  //$savepath = $this->getExercisePath() . "/" . $this->obj_id . "/";
1678  $savepath = $storage->getAbsoluteSubmissionPath();
1679  $cdir = getcwd();
1680 
1681 
1682  // important check: if the directory does not exist
1683  // ILIAS stays in the current directory (echoing only a warning)
1684  // and the zip command below archives the whole ILIAS directory
1685  // (including the data directory) and sends a mega file to the user :-o
1686  if (!is_dir($savepath))
1687  {
1688  return;
1689  }
1690  // Safe mode fix
1691 // chdir($this->getExercisePath());
1692  chdir($storage->getTempPath());
1693  $zip = PATH_TO_ZIP;
1694 
1695  // check first, if we have enough free disk space to copy all files to temporary directory
1696  $tmpdir = ilUtil::ilTempnam();
1697  ilUtil::makeDir($tmpdir);
1698  chdir($tmpdir);
1699 
1700 
1701  $dirsize = 0;
1702  foreach ($members as $id => $object) {
1703  $directory = $savepath.DIRECTORY_SEPARATOR.$id;
1704  $dirsize += ilUtil::dirsize($directory);
1705  }
1706  if ($dirsize > disk_free_space($tmpdir)) {
1707  return -1;
1708  }
1709 
1710  $ass_type = self::lookupType($a_ass_id);
1711 
1712  // copy all member directories to the temporary folder
1713  // switch from id to member name and append the login if the member name is double
1714  // ensure that no illegal filenames will be created
1715  // remove timestamp from filename
1716  $cache = array();
1717  foreach ($members as $id => $user)
1718  {
1719  $sourcedir = $savepath.DIRECTORY_SEPARATOR.$id;
1720  if (!is_dir($sourcedir))
1721  continue;
1722  $userName = ilObjUser::_lookupName($id);
1723  //$directory = ilUtil::getASCIIFilename(trim($userName["lastname"])."_".trim($userName["firstname"]));
1724  $directory = ilUtil::getASCIIFilename(trim($userName["lastname"])."_".
1725  trim($userName["firstname"])."_".trim($userName["login"])."_".$userName["user_id"]);
1726  /*if (array_key_exists($directory, $cache))
1727  {
1728  // first try is to append the login;
1729  $directory = ilUtil::getASCIIFilename($directory."_".trim(ilObjUser::_lookupLogin($id)));
1730  if (array_key_exists($directory, $cache)) {
1731  // second and secure: append the user id as well.
1732  $directory .= "_".$id;
1733  }
1734  }*/
1735 
1736  $cache[$directory] = $directory;
1737  ilUtil::makeDir ($directory);
1738  $sourcefiles = scandir($sourcedir);
1739  $duplicates = array();
1740  foreach ($sourcefiles as $sourcefile) {
1741  if ($sourcefile == "." || $sourcefile == "..")
1742  {
1743  continue;
1744  }
1745 
1746  $targetfile = trim(basename($sourcefile));
1747  $pos = strpos($targetfile, "_");
1748  if ($pos !== false)
1749  {
1750  $targetfile= substr($targetfile, $pos + 1);
1751  }
1752 
1753  // #14536
1754  if(array_key_exists($targetfile, $duplicates))
1755  {
1756  $suffix = strrpos($targetfile, ".");
1757  $targetfile = substr($targetfile, 0, $suffix).
1758  " (".(++$duplicates[$targetfile]).")".
1759  substr($targetfile, $suffix);
1760  }
1761  else
1762  {
1763  $duplicates[$targetfile] = 1;
1764  }
1765 
1766  $targetfile = $directory.DIRECTORY_SEPARATOR.$targetfile;
1767  $sourcefile = $sourcedir.DIRECTORY_SEPARATOR.$sourcefile;
1768 
1769  if (!copy ($sourcefile, $targetfile))
1770  {
1771  //echo 'Could not copy '.$sourcefile.' to '.$targetfile;
1772  $ilias->raiseError('Could not copy '.basename($sourcefile)." to '".$targetfile."'.",
1773  $ilias->error_obj->MESSAGE);
1774  }
1775  else
1776  {
1777  // preserve time stamp
1778  touch($targetfile, filectime($sourcefile));
1779 
1780  // blogs and portfolios are stored as zip and have to be unzipped
1781  if($ass_type == ilExAssignment::TYPE_PORTFOLIO ||
1782  $ass_type == ilExAssignment::TYPE_BLOG)
1783  {
1784  ilUtil::unzip($targetfile);
1785  unlink($targetfile);
1786  }
1787  }
1788 
1789  }
1790  }
1791 
1792  $tmpfile = ilUtil::ilTempnam();
1793  $tmpzipfile = $tmpfile . ".zip";
1794  // Safe mode fix
1795  $zipcmd = $zip." -r ".ilUtil::escapeShellArg($tmpzipfile)." .";
1796  exec($zipcmd);
1797  ilUtil::delDir($tmpdir);
1798 
1799  $assTitle = ilExAssignment::lookupTitle($a_ass_id)."_".$a_ass_id;
1800  chdir($cdir);
1801  ilUtil::deliverFile($tmpzipfile, (strlen($assTitle) == 0
1802  ? strtolower($lng->txt("exc_assignment"))
1803  : $assTitle). ".zip", "", false, true);
1804  }
1805 
1809  function updateNoticeForUser($a_ass_id, $a_user_id, $a_notice)
1810  {
1811  global $ilDB;
1812 
1813  // #12181 / #13741
1814  $ilDB->manipulate("UPDATE exc_mem_ass_status".
1815  " SET notice = ".$ilDB->quote($a_notice, "text").
1816  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
1817  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
1818  " AND ".$ilDB->equalsNot("notice", $a_notice, "text", true));
1819  }
1820 
1824  function _getReturned($a_ass_id)
1825  {
1826  global $ilDB;
1827 
1828  $query = "SELECT DISTINCT(usr_id) as ud FROM exc_mem_ass_status ".
1829  "WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer")." ".
1830  "AND returned = 1";
1831 
1832  $res = $ilDB->query($query);
1833  while($row = $ilDB->fetchObject($res))
1834  {
1835  $usr_ids[] = $row->ud;
1836  }
1837 
1838  return $usr_ids ? $usr_ids : array();
1839  }
1840 
1848  static function getLastSubmission($a_ass_id, $a_user_id)
1849  {
1850  global $ilDB, $lng;
1851 
1852  // team upload?
1853  $user_ids = self::getTeamMembersByAssignmentId($a_ass_id, $a_user_id);
1854  if(!$user_ids)
1855  {
1856  $user_ids = array($a_user_id);
1857  }
1858 
1859  $ilDB->setLimit(1);
1860 
1861  $q = "SELECT obj_id,user_id,ts FROM exc_returned".
1862  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
1863  " AND ".$ilDB->in("user_id", $user_ids, "", "integer").
1864  " ORDER BY ts DESC";
1865 
1866  $usr_set = $ilDB->query($q);
1867 
1868  $array = $ilDB->fetchAssoc($usr_set);
1869  if ($array["ts"]==NULL)
1870  {
1871  return false;
1872  }
1873  else
1874  {
1875  return ilUtil::getMySQLTimestamp($array["ts"]);
1876  }
1877  }
1878 
1882  static function lookupAnyExerciseSent($a_exc_id, $a_ass_id)
1883  {
1884  global $ilDB;
1885 
1886  $q = "SELECT count(*) AS cnt FROM exc_mem_ass_status".
1887  " WHERE NOT sent_time IS NULL".
1888  " AND ass_id = ".$ilDB->quote($a_ass_id, "integer")." ".
1889  " ";
1890  $set = $ilDB->query($q);
1891  $rec = $ilDB->fetchAssoc($set);
1892 
1893  if ($rec["cnt"] > 0)
1894  {
1895  return true;
1896  }
1897  else
1898  {
1899  return false;
1900  }
1901  }
1902 
1907  static function lookupUpdatedSubmission($ass_id, $member_id)
1908  {
1909  global $ilDB, $lng;
1910 
1911  // team upload?
1912  $user_ids = self::getTeamMembersByAssignmentId($ass_id, $member_id);
1913  if(!$user_ids)
1914  {
1915  $user_ids = array($member_id);
1916  }
1917 
1918  $q="SELECT exc_mem_ass_status.status_time, exc_returned.ts ".
1919  "FROM exc_mem_ass_status, exc_returned ".
1920  "WHERE exc_mem_ass_status.status_time < exc_returned.ts ".
1921  "AND NOT exc_mem_ass_status.status_time IS NULL ".
1922  "AND exc_returned.ass_id = exc_mem_ass_status.ass_id ".
1923  "AND exc_returned.user_id = exc_mem_ass_status.usr_id ".
1924  "AND exc_returned.ass_id=".$ilDB->quote($ass_id, "integer").
1925  " AND ".$ilDB->in("exc_returned.user_id", $user_ids, "", "integer");
1926 
1927  $usr_set = $ilDB->query($q);
1928 
1929  $array = $ilDB->fetchAssoc($usr_set);
1930 
1931  if (count($array)==0)
1932  {
1933  return 0;
1934  }
1935  else
1936  {
1937  return 1;
1938  }
1939 
1940  }
1941 
1946  static function lookupNewFiles($ass_id, $member_id)
1947  {
1948  global $ilDB, $ilUser;
1949 
1950  // team upload?
1951  $user_ids = self::getTeamMembersByAssignmentId($ass_id, $member_id);
1952  if(!$user_ids)
1953  {
1954  $user_ids = array($member_id);
1955  }
1956 
1957  $q = "SELECT exc_returned.returned_id AS id ".
1958  "FROM exc_usr_tutor, exc_returned ".
1959  "WHERE exc_returned.ass_id = exc_usr_tutor.ass_id ".
1960  " AND exc_returned.user_id = exc_usr_tutor.usr_id ".
1961  " AND exc_returned.ass_id = ".$ilDB->quote($ass_id, "integer").
1962  " AND ".$ilDB->in("exc_returned.user_id", $user_ids, "", "integer").
1963  " AND exc_usr_tutor.tutor_id = ".$ilDB->quote($ilUser->getId(), "integer").
1964  " AND exc_usr_tutor.download_time < exc_returned.ts ";
1965 
1966  $new_up_set = $ilDB->query($q);
1967 
1968  $new_up = array();
1969  while ($new_up_rec = $ilDB->fetchAssoc($new_up_set))
1970  {
1971  $new_up[] = $new_up_rec["id"];
1972  }
1973 
1974  return $new_up;
1975  }
1976 
1980  function getMemberListData($a_exc_id, $a_ass_id)
1981  {
1982  global $ilDB;
1983 
1984  $mem = array();
1985 
1986  // first get list of members from member table
1987  $set = $ilDB->query("SELECT ud.usr_id, ud.lastname, ud.firstname, ud.login".
1988  " FROM exc_members excm".
1989  " JOIN usr_data ud ON (ud.usr_id = excm.usr_id)".
1990  " WHERE excm.obj_id = ".$ilDB->quote($a_exc_id, "integer"));
1991  while($rec = $ilDB->fetchAssoc($set))
1992  {
1993  $mem[$rec["usr_id"]] =
1994  array(
1995  "name" => $rec["lastname"].", ".$rec["firstname"],
1996  "login" => $rec["login"],
1997  "usr_id" => $rec["usr_id"],
1998  "lastname" => $rec["lastname"],
1999  "firstname" => $rec["firstname"]
2000  );
2001  }
2002 
2003  $q = "SELECT * FROM exc_mem_ass_status ".
2004  "WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer");
2005  $set = $ilDB->query($q);
2006  while($rec = $ilDB->fetchAssoc($set))
2007  {
2008  if (isset($mem[$rec["usr_id"]]))
2009  {
2010  $mem[$rec["usr_id"]]["sent_time"] = $rec["sent_time"];
2011  $mem[$rec["usr_id"]]["submission"] = ilExAssignment::getLastSubmission($a_ass_id, $rec["usr_id"]);
2012  $mem[$rec["usr_id"]]["status_time"] = $rec["status_time"];
2013  $mem[$rec["usr_id"]]["feedback_time"] = $rec["feedback_time"];
2014  $mem[$rec["usr_id"]]["notice"] = $rec["notice"];
2015  $mem[$rec["usr_id"]]["status"] = $rec["status"];
2016  }
2017  }
2018  return $mem;
2019  }
2020 
2024  static function createNewUserRecords($a_user_id, $a_exc_id)
2025  {
2026  global $ilDB;
2027 
2028  $ass_data = ilExAssignment::getAssignmentDataOfExercise($a_exc_id);
2029  foreach ($ass_data as $ass)
2030  {
2031 //echo "-".$ass["id"]."-".$a_user_id."-";
2032  $ilDB->replace("exc_mem_ass_status", array(
2033  "ass_id" => array("integer", $ass["id"]),
2034  "usr_id" => array("integer", $a_user_id)
2035  ), array(
2036  "status" => array("text", "notgraded")
2037  ));
2038  }
2039  }
2040 
2044  static function createNewAssignmentRecords($a_ass_id, $a_exc)
2045  {
2046  global $ilDB;
2047 
2048  include_once("./Modules/Exercise/classes/class.ilExerciseMembers.php");
2049  $exmem = new ilExerciseMembers($a_exc);
2050  $mems = $exmem->getMembers();
2051 
2052  foreach ($mems as $mem)
2053  {
2054  $ilDB->replace("exc_mem_ass_status", array(
2055  "ass_id" => array("integer", $a_ass_id),
2056  "usr_id" => array("integer", $mem)
2057  ), array(
2058  "status" => array("text", "notgraded")
2059  ));
2060  }
2061  }
2062 
2067  function uploadAssignmentFiles($a_files)
2068  {
2069  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
2070  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
2071  $storage->create();
2072  $storage->uploadAssignmentFiles($a_files);
2073  }
2074 
2075  //
2076  // TEAM UPLOAD
2077  //
2078 
2088  function getTeamId($a_user_id, $a_create_on_demand = false)
2089  {
2090  global $ilDB;
2091 
2092  $sql = "SELECT id FROM il_exc_team".
2093  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer").
2094  " AND user_id = ".$ilDB->quote($a_user_id, "integer");
2095  $set = $ilDB->query($sql);
2096  $row = $ilDB->fetchAssoc($set);
2097  $id = $row["id"];
2098 
2099  if(!$id && $a_create_on_demand)
2100  {
2101  $id = $ilDB->nextId("il_exc_team");
2102 
2103  $fields = array("id" => array("integer", $id),
2104  "ass_id" => array("integer", $this->getId()),
2105  "user_id" => array("integer", $a_user_id));
2106  $ilDB->insert("il_exc_team", $fields);
2107 
2108  self::writeTeamLog($id, self::TEAM_LOG_CREATE_TEAM);
2109  self::writeTeamLog($id, self::TEAM_LOG_ADD_MEMBER,
2110  ilObjUser::_lookupFullname($a_user_id));
2111  }
2112 
2113  return $id;
2114  }
2115 
2122  function getTeamMembers($a_team_id)
2123  {
2124  global $ilDB;
2125 
2126  $ids = array();
2127 
2128  $sql = "SELECT user_id".
2129  " FROM il_exc_team".
2130  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer").
2131  " AND id = ".$ilDB->quote($a_team_id, "integer");
2132  $set = $ilDB->query($sql);
2133  while($row = $ilDB->fetchAssoc($set))
2134  {
2135  $ids[] = $row["user_id"];
2136  }
2137 
2138  return $ids;
2139  }
2140 
2147  {
2148  global $ilDB;
2149 
2150  $ids = array();
2151 
2152  $sql = "SELECT user_id".
2153  " FROM il_exc_team".
2154  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer");
2155  $set = $ilDB->query($sql);
2156  while($row = $ilDB->fetchAssoc($set))
2157  {
2158  $ids[] = $row["user_id"];
2159  }
2160 
2161  return $ids;
2162  }
2163 
2171  function addTeamMember($a_team_id, $a_user_id, $a_exc_ref_id = null)
2172  {
2173  global $ilDB;
2174 
2175  $members = $this->getTeamMembers($a_team_id);
2176  if(!in_array($a_user_id, $members))
2177  {
2178  $fields = array("id" => array("integer", $a_team_id),
2179  "ass_id" => array("integer", $this->getId()),
2180  "user_id" => array("integer", $a_user_id));
2181  $ilDB->insert("il_exc_team", $fields);
2182 
2183  if($a_exc_ref_id)
2184  {
2185  $this->sendNotification($a_exc_ref_id, $a_user_id, "add");
2186  }
2187 
2188  self::writeTeamLog($a_team_id, self::TEAM_LOG_ADD_MEMBER,
2189  ilObjUser::_lookupFullname($a_user_id));
2190  }
2191  }
2192 
2200  function removeTeamMember($a_team_id, $a_user_id, $a_exc_ref_id)
2201  {
2202  global $ilDB;
2203 
2204  $sql = "DELETE FROM il_exc_team".
2205  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer").
2206  " AND id = ".$ilDB->quote($a_team_id, "integer").
2207  " AND user_id = ".$ilDB->quote($a_user_id, "integer");
2208  $ilDB->manipulate($sql);
2209 
2210  $this->sendNotification($a_exc_ref_id, $a_user_id, "rmv");
2211 
2212  self::writeTeamLog($a_team_id, self::TEAM_LOG_REMOVE_MEMBER,
2213  ilObjUser::_lookupFullname($a_user_id));
2214  }
2215 
2223  public static function getTeamMembersByAssignmentId($a_ass_id, $a_user_id)
2224  {
2225  global $ilDB;
2226 
2227  $ids = array();
2228 
2229  $team_id = self::getTeamIdByAssignment($a_ass_id, $a_user_id);
2230  if($team_id)
2231  {
2232  $set = $ilDB->query("SELECT user_id".
2233  " FROM il_exc_team".
2234  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
2235  " AND id = ". $ilDB->quote($team_id, "integer"));
2236  while($row = $ilDB->fetchAssoc($set))
2237  {
2238  $ids[] = $row["user_id"];
2239  }
2240  }
2241 
2242  return $ids;
2243  }
2244 
2252  public static function getTeamIdByAssignment($a_ass_id, $a_user_id)
2253  {
2254  global $ilDB;
2255 
2256  $result = $ilDB->query("SELECT type".
2257  " FROM exc_assignment".
2258  " WHERE id = ".$ilDB->quote($a_ass_id, "integer"));
2259  $type = $ilDB->fetchAssoc($result);
2260 
2261  if($type["type"] == self::TYPE_UPLOAD_TEAM)
2262  {
2263  $set = $ilDB->query("SELECT id".
2264  " FROM il_exc_team".
2265  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
2266  " AND user_id = ".$ilDB->quote($a_user_id, "integer"));
2267  $team_id = $ilDB->fetchAssoc($set);
2268  return $team_id["id"];
2269  }
2270  }
2271 
2278  public static function getAssignmentTeamMap($a_ass_id)
2279  {
2280  global $ilDB;
2281 
2282  $map = array();
2283 
2284  $sql = "SELECT * FROM il_exc_team".
2285  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer");
2286  $set = $ilDB->query($sql);
2287  while($row = $ilDB->fetchAssoc($set))
2288  {
2289  $map[$row["user_id"]] = $row["id"];
2290  }
2291 
2292  return $map;
2293  }
2294 
2302  public static function writeTeamLog($a_team_id, $a_action, $a_details = null)
2303  {
2304  global $ilDB, $ilUser;
2305 
2306  $fields = array(
2307  "team_id" => array("integer", $a_team_id),
2308  "user_id" => array("integer", $ilUser->getId()),
2309  "action" => array("integer", $a_action),
2310  "details" => array("text", $a_details),
2311  "tstamp" => array("integer", time())
2312  );
2313 
2314  $ilDB->insert("il_exc_team_log", $fields);
2315  }
2316 
2323  public static function getTeamLog($a_team_id)
2324  {
2325  global $ilDB;
2326 
2327  $res = array();
2328 
2329  $sql = "SELECT * FROM il_exc_team_log".
2330  " WHERE team_id = ".$ilDB->quote($a_team_id, "integer").
2331  " ORDER BY tstamp DESC";
2332  $set = $ilDB->query($sql);
2333  while($row = $ilDB->fetchAssoc($set))
2334  {
2335  $res[] = $row;
2336  }
2337  return $res;
2338  }
2339 
2347  public function sendNotification($a_exc_ref_id, $a_user_id, $a_action)
2348  {
2349  global $ilUser;
2350 
2351  // no need to notify current user
2352  if($ilUser->getId() == $a_user_id)
2353  {
2354  return;
2355  }
2356 
2357  include_once "./Services/Notification/classes/class.ilSystemNotification.php";
2358  $ntf = new ilSystemNotification();
2359  $ntf->setLangModules(array("exc"));
2360  $ntf->setRefId($a_exc_ref_id);
2361  $ntf->setChangedByUserId($ilUser->getId());
2362  $ntf->setSubjectLangId('exc_team_notification_subject_'.$a_action);
2363  $ntf->setIntroductionLangId('exc_team_notification_body_'.$a_action);
2364  $ntf->addAdditionalInfo("exc_assignment", $this->getTitle());
2365  $ntf->setGotoLangId('exc_team_notification_link');
2366  $ntf->setReasonLangId('exc_team_notification_reason');
2367  $ntf->sendMail(array($a_user_id));
2368  }
2369 
2370  public static function getDownloadedFilesInfoForTableGUIS($a_parent_obj, $a_exercise_id, $a_ass_type, $a_ass_id, $a_user_id, $a_parent_cmd = null)
2371  {
2372  global $lng, $ilCtrl;
2373 
2374  $result = array();
2375  $result["files"]["count"] = "---";
2376 
2377  $ilCtrl->setParameter($a_parent_obj, "ass_id", $a_ass_id);
2378 
2379  // submission:
2380  // see if files have been resubmmited after solved
2381  $last_sub = self::getLastSubmission($a_ass_id, $a_user_id);
2382  if ($last_sub)
2383  {
2384  $last_sub = ilDatePresentation::formatDate(new ilDateTime($last_sub,IL_CAL_DATETIME));
2385  }
2386  else
2387  {
2388  $last_sub = "---";
2389  }
2390  /* #13741 - status_time has been reduced to grading (mark/status)
2391  if (ilExAssignment::lookupUpdatedSubmission($a_ass_id, $a_user_id) == 1)
2392  {
2393  $last_sub = "<b>".$last_sub."</b>";
2394  }
2395  */
2396  $result["last_submission"]["txt"] = $lng->txt("exc_last_submission");
2397  $result["last_submission"]["value"] = $last_sub;
2398 
2399  // assignment type specific
2400  switch($a_ass_type)
2401  {
2403  // data is merged by team - see above
2404  // fallthrough
2405 
2407  // nr of submitted files
2408  $result["files"]["txt"] = $lng->txt("exc_files_returned");
2409  $sub_cnt = count(ilExAssignment::getDeliveredFiles($a_exercise_id, $a_ass_id, $a_user_id));
2410  $new = ilExAssignment::lookupNewFiles($a_ass_id, $a_user_id);
2411  if (count($new) > 0)
2412  {
2413  $sub_cnt.= " ".sprintf($lng->txt("cnt_new"),count($new));
2414  }
2415  $result["files"]["count"] = $sub_cnt;
2416 
2417  // download command
2418  $ilCtrl->setParameter($a_parent_obj, "member_id", $a_user_id);
2419 
2420  if ($sub_cnt > 0)
2421  {
2422  $result["files"]["download_url"] =
2423  $ilCtrl->getLinkTarget($a_parent_obj, "downloadReturned");
2424 
2425  if (count($new) <= 0)
2426  {
2427  $result["files"]["download_txt"] = $lng->txt("exc_download_files");
2428  }
2429  else
2430  {
2431  $result["files"]["download_txt"] = $lng->txt("exc_download_all");
2432  }
2433 
2434  // download new files only
2435  if (count($new) > 0)
2436  {
2437  $result["files"]["download_new_url"] =
2438  $ilCtrl->getLinkTarget($a_parent_obj, "downloadNewReturned");
2439 
2440  $result["files"]["download_new_txt"] = $lng->txt("exc_download_new");
2441  }
2442  }
2443  break;
2444 
2446  $result["files"]["txt"] =$lng->txt("exc_blog_returned");
2447  $blogs = ilExAssignment::getDeliveredFiles($a_exercise_id, $a_ass_id, $a_user_id);
2448  if($blogs)
2449  {
2450  $blogs = array_pop($blogs);
2451  if($blogs && substr($blogs["filename"], -1) != "/")
2452  {
2453  $result["files"]["count"] = 1;
2454 
2455  $ilCtrl->setParameter($a_parent_obj, "member_id", $a_user_id);
2456  $result["files"]["download_url"] =
2457  $ilCtrl->getLinkTarget($a_parent_obj, "downloadReturned");
2458  $ilCtrl->setParameter($a_parent_obj, "member_id", "");
2459 
2460  $result["files"]["download_txt"] = $lng->txt("exc_download_files");
2461  }
2462  }
2463  break;
2464 
2466  $result["files"]["txt"] = $lng->txt("exc_portfolio_returned");
2467  $portfolios = ilExAssignment::getDeliveredFiles($a_exercise_id, $a_ass_id, $a_user_id);
2468  if($portfolios)
2469  {
2470  $portfolios = array_pop($portfolios);
2471  if($portfolios && substr($portfolios["filename"], -1) != "/")
2472  {
2473  $result["files"]["count"] = 1;
2474 
2475  $ilCtrl->setParameter($a_parent_obj, "member_id", $a_user_id);
2476  $result["files"]["download_url"] =
2477  $ilCtrl->getLinkTarget($a_parent_obj, "downloadReturned");
2478  $ilCtrl->setParameter($a_parent_obj, "member_id", "");
2479 
2480  $result["files"]["download_txt"] = $lng->txt("exc_download_files");
2481  }
2482  }
2483  break;
2484 
2486  $result["files"]["txt"] = $lng->txt("exc_files_returned_text");
2487  $files = ilExAssignment::getDeliveredFiles($a_exercise_id, $a_ass_id, $a_user_id);
2488  if($files)
2489  {
2490  $result["files"]["count"] = 1;
2491 
2492  $files = array_shift($files);
2493  if(trim($files["atext"]))
2494  {
2495  // #11397
2496  if($a_parent_cmd)
2497  {
2498  $ilCtrl->setParameter($a_parent_obj, "grd", (($a_parent_cmd == "members") ? 1 : 2));
2499  }
2500  $ilCtrl->setParameter($a_parent_obj, "member_id", $a_user_id);
2501  $result["files"]["download_url"] =
2502  $ilCtrl->getLinkTarget($a_parent_obj, "showAssignmentText");
2503  $ilCtrl->setParameter($a_parent_obj, "member_id", "");
2504  $ilCtrl->setParameter($a_parent_obj, "grd", "");
2505 
2506  $result["files"]["download_txt"] = $lng->txt("exc_text_assignment_show");
2507  }
2508  }
2509  break;
2510  }
2511 
2512  return $result;
2513  }
2514 
2515  public function hasPeerReviewGroups()
2516  {
2517  global $ilDB;
2518 
2519  $set = $ilDB->query("SELECT count(*) cnt".
2520  " FROM exc_assignment_peer".
2521  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer"));
2522  $cnt = $ilDB->fetchAssoc($set);
2523  return (bool)$cnt["cnt"];
2524  }
2525 
2526  protected function getValidPeerReviewUsers()
2527  {
2528  global $ilDB;
2529 
2530  $user_ids = array();
2531 
2532  // returned / assigned ?!
2533  $set = $ilDB->query("SELECT DISTINCT(user_id)".
2534  " FROM exc_returned".
2535  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer"));
2536  while($row = $ilDB->fetchAssoc($set))
2537  {
2538  $user_ids[] = $row["user_id"];
2539  }
2540 
2541  return $user_ids;
2542  }
2543 
2544  protected function initPeerReviews()
2545  {
2546  global $ilDB;
2547 
2548  // only if assignment is through
2549  if(!$this->getDeadline() || $this->getDeadline() > time())
2550  {
2551  return false;
2552  }
2553 
2554  if(!$this->hasPeerReviewGroups())
2555  {
2556  $user_ids = $this->getValidPeerReviewUsers();
2557 
2558  // forever alone
2559  if(sizeof($user_ids) < 2)
2560  {
2561  return false;
2562  }
2563 
2564  $rater_ids = $user_ids;
2565  $matrix = array();
2566 
2567  $max = min(sizeof($user_ids)-1, $this->getPeerReviewMin());
2568  for($loop = 0; $loop < $max; $loop++)
2569  {
2570  $run_ids = array_combine($user_ids, $user_ids);
2571 
2572  foreach($rater_ids as $rater_id)
2573  {
2574  $possible_peer_ids = $run_ids;
2575 
2576  // may not rate himself
2577  unset($possible_peer_ids[$rater_id]);
2578 
2579  // already has linked peers
2580  if(array_key_exists($rater_id, $matrix))
2581  {
2582  $possible_peer_ids = array_diff($possible_peer_ids, $matrix[$rater_id]);
2583  }
2584 
2585  // #15665 / #15883
2586  if(!sizeof($possible_peer_ids))
2587  {
2588  // no more possible peers left? start over with all valid users
2589  $run_ids = array_combine($user_ids, $user_ids);
2590 
2591  // see above
2592  $possible_peer_ids = $run_ids;
2593 
2594  // may not rate himself
2595  unset($possible_peer_ids[$rater_id]);
2596 
2597  // already has linked peers
2598  if(array_key_exists($rater_id, $matrix))
2599  {
2600  $possible_peer_ids = array_diff($possible_peer_ids, $matrix[$rater_id]);
2601  }
2602  }
2603 
2604  // #14947
2605  if(sizeof($possible_peer_ids))
2606  {
2607  $peer_id = array_rand($possible_peer_ids);
2608  if(!array_key_exists($rater_id, $matrix))
2609  {
2610  $matrix[$rater_id] = array();
2611  }
2612  $matrix[$rater_id][] = $peer_id;
2613  }
2614 
2615  // remove peer_id from possible ids in this run
2616  unset($run_ids[$peer_id]);
2617  }
2618  }
2619 
2620  foreach($matrix as $rater_id => $peer_ids)
2621  {
2622  foreach($peer_ids as $peer_id)
2623  {
2624  $ilDB->manipulate("INSERT INTO exc_assignment_peer".
2625  " (ass_id, giver_id, peer_id)".
2626  " VALUES (".$ilDB->quote($this->getId(), "integer").
2627  ", ".$ilDB->quote($rater_id, "integer").
2628  ", ".$ilDB->quote($peer_id, "integer").")");
2629  }
2630  }
2631 
2632  }
2633  return true;
2634  }
2635 
2636  public function resetPeerReviewFileUploads()
2637  {
2638  if($this->hasPeerReviewFileUpload())
2639  {
2640  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
2641  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
2642  $storage->deletePeerReviewUploads();
2643  }
2644  }
2645 
2646  public function resetPeerReviews()
2647  {
2648  global $ilDB;
2649 
2650  if($this->hasPeerReviewGroups())
2651  {
2652  // ratings
2653  foreach($this->getAllPeerReviews(false) as $peer_id => $reviews)
2654  {
2655  foreach($reviews as $giver_id => $review)
2656  {
2658  $peer_id, "peer", $giver_id);
2659  }
2660  }
2661 
2662  // files
2663  $this->resetPeerReviewFileUploads();
2664 
2665  // peer groups
2666  $ilDB->manipulate("DELETE FROM exc_assignment_peer".
2667  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer"));
2668  }
2669  }
2670 
2671  public function validatePeerReviewGroups()
2672  {
2673  if($this->hasPeerReviewGroups())
2674  {
2675  include_once "./Modules/Exercise/classes/class.ilExerciseMembers.php";
2676  $all_exc = ilExerciseMembers::_getMembers($this->getExerciseId());
2677  $all_valid = $this->getValidPeerReviewUsers(); // only returned
2678 
2679  $peer_ids = $invalid_peer_ids = $invalid_giver_ids = $all_reviews = array();
2680  foreach($this->getAllPeerReviews(false) as $peer_id => $reviews)
2681  {
2682  $peer_ids[] = $peer_id;
2683 
2684  if(!in_array($peer_id, $all_valid) ||
2685  !in_array($peer_id, $all_exc))
2686  {
2687  $invalid_peer_ids[] = $peer_id;
2688  }
2689  foreach($reviews as $giver_id => $review)
2690  {
2691  if(!in_array($giver_id, $all_valid) ||
2692  !in_array($giver_id, $all_exc))
2693  {
2694  $invalid_giver_ids[] = $giver_id;
2695  }
2696  else
2697  {
2698  $valid = (trim($review[0]) || $review[1]);
2699  $all_reviews[$peer_id][$giver_id] = $valid;
2700  }
2701  }
2702  }
2703  $invalid_giver_ids = array_unique($invalid_giver_ids);
2704 
2705  $missing_user_ids = array();
2706  foreach($all_valid as $user_id)
2707  {
2708  // a missing peer is also a missing giver
2709  if(!in_array($user_id, $peer_ids))
2710  {
2711  $missing_user_ids[] = $user_id;
2712  }
2713  }
2714 
2715  $not_returned_ids = array();
2716  foreach($all_exc as $user_id)
2717  {
2718  if(!in_array($user_id, $all_valid))
2719  {
2720  $not_returned_ids[] = $user_id;
2721  }
2722  }
2723 
2724  return array(
2725  "invalid" => (sizeof($missing_user_ids) ||
2726  sizeof($invalid_peer_ids) ||
2727  sizeof($invalid_giver_ids)),
2728  "missing_user_ids" => $missing_user_ids,
2729  "not_returned_ids" => $not_returned_ids,
2730  "invalid_peer_ids" => $invalid_peer_ids,
2731  "invalid_giver_ids" => $invalid_giver_ids,
2732  "reviews" => $all_reviews);
2733  }
2734  }
2735 
2736  public function getPeerReviewsByGiver($a_user_id)
2737  {
2738  global $ilDB;
2739 
2740  $res = array();
2741 
2742  if($this->initPeerReviews())
2743  {
2744  $set = $ilDB->query("SELECT *".
2745  " FROM exc_assignment_peer".
2746  " WHERE giver_id = ".$ilDB->quote($a_user_id, "integer").
2747  " AND ass_id = ".$ilDB->quote($this->getId(), "integer").
2748  " ORDER BY peer_id");
2749  while($row = $ilDB->fetchAssoc($set))
2750  {
2751  $res[] = $row;
2752  }
2753  }
2754 
2755  return $res;
2756  }
2757 
2758  protected static function validatePeerReview(array $a_data, $a_rating = null)
2759  {
2760  $valid = false;
2761 
2762  // comment
2763  if(trim($a_data["pcomment"]))
2764  {
2765  $valid = true;
2766  }
2767 
2768  // rating
2769  if(!$valid)
2770  {
2771  if($a_rating === null)
2772  {
2773  include_once './Services/Rating/classes/class.ilRating.php';
2774  $valid = (bool)round(ilRating::getRatingForUserAndObject($a_data["ass_id"],
2775  "ass", $a_data["peer_id"], "peer", $a_data["giver_id"]));
2776  }
2777  else if($a_rating)
2778  {
2779  $valid = true;
2780  }
2781  }
2782 
2783  // file(s)
2784  if(!$valid)
2785  {
2786  $ass = new self($a_data["ass_id"]);
2787  $valid = (bool)sizeof($ass->getPeerUploadFiles($a_data["peer_id"], $a_data["giver_id"]));
2788  }
2789 
2790  return $valid;
2791  }
2792 
2793  public function getPeerReviewsByPeerId($a_user_id, $a_only_valid = false)
2794  {
2795  global $ilDB;
2796 
2797  $res = array();
2798 
2799  $set = $ilDB->query("SELECT *".
2800  " FROM exc_assignment_peer".
2801  " WHERE peer_id = ".$ilDB->quote($a_user_id, "integer").
2802  " AND ass_id = ".$ilDB->quote($this->getId(), "integer").
2803  " ORDER BY peer_id");
2804  while($row = $ilDB->fetchAssoc($set))
2805  {
2806  if(!$a_only_valid ||
2807  self::validatePeerReview($row))
2808  {
2809  $res[] = $row;
2810  }
2811  }
2812 
2813  return $res;
2814  }
2815 
2816  public function getAllPeerReviews($a_validate = true)
2817  {
2818  global $ilDB;
2819 
2820  $res = array();
2821 
2822  include_once './Services/Rating/classes/class.ilRating.php';
2823 
2824  $set = $ilDB->query("SELECT *".
2825  " FROM exc_assignment_peer".
2826  " WHERE ass_id = ".$ilDB->quote($this->getId(), "integer").
2827  " ORDER BY peer_id");
2828  while($row = $ilDB->fetchAssoc($set))
2829  {
2830  $rating = round(ilRating::getRatingForUserAndObject($this->getId(),
2831  "ass", $row["peer_id"], "peer", $row["giver_id"]));
2832 
2833  if(!$a_validate ||
2834  self::validatePeerReview($row, $rating))
2835  {
2836  $res[$row["peer_id"]][$row["giver_id"]] = array($row["pcomment"], $rating);
2837  }
2838  }
2839 
2840  return $res;
2841  }
2842 
2843  public function hasPeerReviewAccess($a_peer_id)
2844  {
2845  global $ilDB, $ilUser;
2846 
2847  $set = $ilDB->query("SELECT ass_id".
2848  " FROM exc_assignment_peer".
2849  " WHERE giver_id = ".$ilDB->quote($ilUser->getId(), "integer").
2850  " AND peer_id = ".$ilDB->quote($a_peer_id, "integer").
2851  " AND ass_id = ".$ilDB->quote($this->getId(), "integer"));
2852  $row = $ilDB->fetchAssoc($set);
2853  return (bool)$row["ass_id"];
2854  }
2855 
2856  public function updatePeerReviewTimestamp($a_peer_id)
2857  {
2858  global $ilDB, $ilUser;
2859 
2860  $ilDB->manipulate("UPDATE exc_assignment_peer".
2861  " SET tstamp = ".$ilDB->quote(ilUtil::now(), "timestamp").
2862  " WHERE giver_id = ".$ilDB->quote($ilUser->getId(), "integer").
2863  " AND peer_id = ".$ilDB->quote($a_peer_id, "integer").
2864  " AND ass_id = ".$ilDB->quote($this->getId(), "integer"));
2865  }
2866 
2867  public function getPeerUploadFiles($a_peer_id, $a_giver_id)
2868  {
2869  if(!$this->hasPeerReviewFileUpload())
2870  {
2871  return array();
2872  }
2873  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
2874  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
2875  $path = $storage->getPeerReviewUploadPath($a_peer_id, $a_giver_id);
2876  return glob($path."/*.*");
2877  }
2878 
2879  public function updatePeerReviewComment($a_peer_id, $a_comment)
2880  {
2881  global $ilDB, $ilUser;
2882 
2883  $sql = "UPDATE exc_assignment_peer".
2884  " SET tstamp = ".$ilDB->quote(ilUtil::now(), "timestamp").
2885  ",pcomment = ".$ilDB->quote(trim($a_comment), "text").
2886  " WHERE giver_id = ".$ilDB->quote($ilUser->getId(), "integer").
2887  " AND peer_id = ".$ilDB->quote($a_peer_id, "integer").
2888  " AND ass_id = ".$ilDB->quote($this->getId(), "integer");
2889 
2890  $ilDB->manipulate($sql);
2891  }
2892 
2893  public static function countGivenFeedback($a_ass_id)
2894  {
2895  global $ilDB, $ilUser;
2896 
2897  $cnt = 0;
2898 
2899  include_once './Services/Rating/classes/class.ilRating.php';
2900 
2901  $set = $ilDB->query("SELECT *".
2902  " FROM exc_assignment_peer".
2903  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer").
2904  " AND giver_id = ".$ilDB->quote($ilUser->getId(), "integer"));
2905  while($row = $ilDB->fetchAssoc($set))
2906  {
2907  if(self::validatePeerReview($row))
2908  {
2909  $cnt++;
2910  }
2911  }
2912 
2913  return $cnt;
2914  }
2915 
2916  public static function getNumberOfMissingFeedbacks($a_ass_id, $a_min)
2917  {
2918  global $ilDB;
2919 
2920  // check if number of returned assignments is lower than assignment peer min
2921  $set = $ilDB->query("SELECT COUNT(DISTINCT(user_id)) cnt".
2922  " FROM exc_returned".
2923  " WHERE ass_id = ".$ilDB->quote($a_ass_id, "integer"));
2924  $cnt = $ilDB->fetchAssoc($set);
2925  $cnt = (int)$cnt["cnt"];
2926 
2927  // forever alone
2928  if($cnt < 2)
2929  {
2930  return;
2931  }
2932 
2933  $a_min = min($cnt-1, $a_min);
2934 
2935  return max(0, $a_min-self::countGivenFeedback($a_ass_id));
2936  }
2937 
2938  public static function getPendingFeedbackNotifications()
2939  {
2940  global $ilDB;
2941 
2942  $res = array();
2943 
2944  $set = $ilDB->query("SELECT id,fb_file FROM exc_assignment".
2945  " WHERE fb_cron = ".$ilDB->quote(1, "integer").
2946  " AND fb_date = ".$ilDB->quote(self::FEEDBACK_DATE_DEADLINE, "integer").
2947  " AND time_stamp IS NOT NULL".
2948  " AND time_stamp > ".$ilDB->quote(0, "integer").
2949  " AND time_stamp < ".$ilDB->quote(time(), "integer").
2950  " AND fb_cron_done = ".$ilDB->quote(0, "integer"));
2951  while($row = $ilDB->fetchAssoc($set))
2952  {
2953  if(trim($row["fb_file"]))
2954  {
2955  $res[] = $row["id"];
2956  }
2957  }
2958 
2959  return $res;
2960  }
2961 
2962  public function sendFeedbackNotifications($a_ass_id, $a_user_id = null)
2963  {
2964  global $ilDB;
2965 
2966  $ass = new self($a_ass_id);
2967 
2968  // valid assignment?
2969  if(!$ass->hasFeedbackCron() || !$ass->getFeedbackFile())
2970  {
2971  return false;
2972  }
2973 
2974  if(!$a_user_id)
2975  {
2976  // already done?
2977  $set = $ilDB->query("SELECT fb_cron_done".
2978  " FROM exc_assignment".
2979  " WHERE id = ".$ilDB->quote($a_ass_id, "integer"));
2980  $row = $ilDB->fetchAssoc($set);
2981  if($row["fb_cron_done"])
2982  {
2983  return false;
2984  }
2985  }
2986 
2987  include_once "./Services/Notification/classes/class.ilSystemNotification.php";
2988  $ntf = new ilSystemNotification();
2989  $ntf->setLangModules(array("exc"));
2990  $ntf->setObjId($ass->getExerciseId());
2991  $ntf->setSubjectLangId("exc_feedback_notification_subject");
2992  $ntf->setIntroductionLangId("exc_feedback_notification_body");
2993  $ntf->addAdditionalInfo("exc_assignment", $ass->getTitle());
2994  $ntf->setGotoLangId("exc_feedback_notification_link");
2995  $ntf->setReasonLangId("exc_feedback_notification_reason");
2996 
2997  if(!$a_user_id)
2998  {
2999  include_once "./Modules/Exercise/classes/class.ilExerciseMembers.php";
3000  $ntf->sendMail(ilExerciseMembers::_getMembers($ass->getExerciseId()));
3001 
3002  $ilDB->manipulate("UPDATE exc_assignment".
3003  " SET fb_cron_done = ".$ilDB->quote(1, "integer").
3004  " WHERE id = ".$ilDB->quote($a_ass_id, "integer"));
3005  }
3006  else
3007  {
3008  $ntf->sendMail(array($a_user_id));
3009  }
3010 
3011  return true;
3012  }
3013 
3017 
3022  {
3023  global $ilDB;
3024 
3025 
3026  // send and delete the zip file
3027  $deliverFilename = trim(str_replace(" ", "_", $this->getTitle()."_".$this->getId()));
3028  $deliverFilename = ilUtil::getASCIIFilename($deliverFilename);
3029  $deliverFilename = "multi_feedback_".$deliverFilename;
3030 
3031  $exc = new ilObjExercise($this->getExerciseId(), false);
3032 
3033  $cdir = getcwd();
3034 
3035  // create temporary directoy
3036  $tmpdir = ilUtil::ilTempnam();
3037  ilUtil::makeDir($tmpdir);
3038  $mfdir = $tmpdir."/".$deliverFilename;
3039  ilUtil::makeDir($mfdir);
3040 
3041  // create subfolders <lastname>_<firstname>_<id> for each participant
3042  include_once("./Modules/Exercise/classes/class.ilExerciseMembers.php");
3043  $exmem = new ilExerciseMembers($exc);
3044  $mems = $exmem->getMembers();
3045 
3046  foreach ($mems as $mem)
3047  {
3048  $name = ilObjUser::_lookupName($mem);
3049  $subdir = $name["lastname"]."_".$name["firstname"]."_".$name["login"]."_".$name["user_id"];
3050  $subdir = ilUtil::getASCIIFilename($subdir);
3051  ilUtil::makeDir($mfdir."/".$subdir);
3052  }
3053 
3054  // create the zip file
3055  chdir($tmpdir);
3056  $tmpzipfile = $tmpdir."/multi_feedback.zip";
3057  ilUtil::zip($tmpdir, $tmpzipfile, true);
3058  chdir($cdir);
3059 
3060 
3061  ilUtil::deliverFile($tmpzipfile, $deliverFilename.".zip", "", false, true);
3062  }
3063 
3070  function uploadMultiFeedbackFile($a_file)
3071  {
3072  global $lng, $ilUser;
3073 
3074  include_once("./Modules/Exercise/exceptions/class.ilExerciseException.php");
3075  if (!is_file($a_file["tmp_name"]))
3076  {
3077  throw new ilExerciseException($lng->txt("exc_feedback_file_could_not_be_uploaded"));
3078  }
3079 
3080  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
3081  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
3082  $mfu = $storage->getMultiFeedbackUploadPath($ilUser->getId());
3083  ilUtil::delDir($mfu, true);
3084  ilUtil::moveUploadedFile($a_file["tmp_name"], "multi_feedback.zip", $mfu."/"."multi_feedback.zip");
3085  ilUtil::unzip($mfu."/multi_feedback.zip", true);
3086  $subdirs = ilUtil::getDir($mfu);
3087  $subdir = "notfound";
3088  foreach ($subdirs as $s => $j)
3089  {
3090  if ($j["type"] == "dir" && substr($s, 0, 14) == "multi_feedback")
3091  {
3092  $subdir = $s;
3093  }
3094  }
3095 
3096  if (!is_dir($mfu."/".$subdir))
3097  {
3098  throw new ilExerciseException($lng->txt("exc_no_feedback_dir_found_in_zip"));
3099  }
3100 
3101  return true;
3102  }
3103 
3110  function getMultiFeedbackFiles($a_user_id = 0)
3111  {
3112  global $ilUser;
3113 
3114  if ($a_user_id == 0)
3115  {
3116  $a_user_id = $ilUser->getId();
3117  }
3118 
3119  $mf_files = array();
3120 
3121  // get members
3122  $exc = new ilObjExercise($this->getExerciseId(), false);
3123  include_once("./Modules/Exercise/classes/class.ilExerciseMembers.php");
3124  $exmem = new ilExerciseMembers($exc);
3125  $mems = $exmem->getMembers();
3126 
3127  // read mf directory
3128  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
3129  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
3130  $mfu = $storage->getMultiFeedbackUploadPath($ilUser->getId());
3131 
3132  // get subdir that starts with multi_feedback
3133  $subdirs = ilUtil::getDir($mfu);
3134  $subdir = "notfound";
3135  foreach ($subdirs as $s => $j)
3136  {
3137  if ($j["type"] == "dir" && substr($s, 0, 14) == "multi_feedback")
3138  {
3139  $subdir = $s;
3140  }
3141  }
3142 
3143  $items = ilUtil::getDir($mfu."/".$subdir);
3144  foreach ($items as $k => $i)
3145  {
3146  // check directory
3147  if ($i["type"] == "dir" && !in_array($k, array(".", "..")))
3148  {
3149  // check if valid member id is given
3150  $parts = explode("_", $i["entry"]);
3151  $user_id = (int) $parts[count($parts) - 1];
3152  if (in_array($user_id, $mems))
3153  {
3154  // read dir of user
3155  $name = ilObjUser::_lookupName($user_id);
3156  $files = ilUtil::getDir($mfu."/".$subdir."/".$k);
3157  foreach ($files as $k2 => $f)
3158  {
3159  // append files to array
3160  if ($f["type"] == "file" && substr($k2, 0, 1) != ".")
3161  {
3162  $mf_files[] = array(
3163  "lastname" => $name["lastname"],
3164  "firstname" => $name["firstname"],
3165  "login" => $name["login"],
3166  "user_id" => $name["user_id"],
3167  "full_path" => $mfu."/".$subdir."/".$k."/".$k2,
3168  "file" => $k2);
3169  }
3170  }
3171  }
3172  }
3173  }
3174  return $mf_files;
3175  }
3176 
3184  {
3185  global $lng, $ilUser;
3186 
3187  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
3188  $storage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
3189  $mfu = $storage->getMultiFeedbackUploadPath($ilUser->getId());
3190  ilUtil::delDir($mfu);
3191  }
3192 
3199  function saveMultiFeedbackFiles($a_files)
3200  {
3201  $exc = new ilObjExercise($this->getExerciseId(), false);
3202 
3203  include_once("./Modules/Exercise/classes/class.ilFSStorageExercise.php");
3204  $fstorage = new ilFSStorageExercise($this->getExerciseId(), $this->getId());
3205  $fstorage->create();
3206 
3207  $team_map = array();
3208 
3209  $mf_files = $this->getMultiFeedbackFiles();
3210  foreach ($mf_files as $f)
3211  {
3212  $user_id = $f["user_id"];
3213  $file_path = $f["full_path"];
3214  $file_name = $f["file"];
3215 
3216  // if checked in confirmation gui
3217  if ($a_files[$user_id][md5($file_name)] != "")
3218  {
3219  // #14294 - team assignment
3220  if ($this->getType() == ilExAssignment::TYPE_UPLOAD_TEAM)
3221  {
3222  // just once for each user
3223  if (!array_key_exists($user_id, $team_map))
3224  {
3225  $team_id = $this->getTeamId($user_id);
3226  $team_map[$user_id]["team_id"] = "t".$team_id;
3227 
3228  $team_map[$user_id]["noti_rec_ids"] = array();
3229  foreach ($this->getTeamMembers($team_id) as $team_user_id)
3230  {
3231  $team_map[$user_id]["noti_rec_ids"][] = $team_user_id;
3232  }
3233  }
3234 
3235  $feedback_id = $team_map[$user_id]["team_id"];
3236  $noti_rec_ids = $team_map[$user_id]["noti_rec_ids"];
3237  }
3238  else
3239  {
3240  $feedback_id = $user_id;
3241  $noti_rec_ids = array($user_id);
3242  }
3243 
3244  if ($feedback_id)
3245  {
3246  $fb_path = $fstorage->getFeedbackPath($feedback_id);
3247  $target = $fb_path."/".$file_name;
3248  if (is_file($target))
3249  {
3250  unlink($target);
3251  }
3252  // rename file
3253  rename($file_path, $target);
3254 
3255  if ($noti_rec_ids)
3256  {
3257  $exc->sendFeedbackFileNotification($file_name, $noti_rec_ids,
3258  (int) $this->getId());
3259  }
3260  }
3261  }
3262  }
3263 
3264  $this->clearMultiFeedbackDirectory();
3265  }
3266 
3272  protected function handleCalendarEntries($a_event)
3273  {
3274  global $ilAppEventHandler;
3275 
3276  $dl_id = $this->getId()."0";
3277  $fbdl_id = $this->getId()."1";
3278 
3279  $context_ids = array($dl_id, $fbdl_id);
3280  $apps = array();
3281 
3282  if($a_event != "delete")
3283  {
3284  include_once "Services/Calendar/classes/class.ilCalendarAppointmentTemplate.php";
3285 
3286  if($this->getDeadline())
3287  {
3288  $app = new ilCalendarAppointmentTemplate($dl_id);
3289  $app->setTranslationType(IL_CAL_TRANSLATION_SYSTEM);
3290  $app->setSubtitle("cal_exc_deadline");
3291  $app->setTitle($this->getTitle());
3292  $app->setFullday(false);
3293  $app->setStart(new ilDateTime($this->getDeadline(), IL_CAL_UNIX));
3294 
3295  $apps[] = $app;
3296  }
3297 
3298  if($this->getPeerReview() &&
3299  $this->getPeerReviewDeadline())
3300  {
3301  $app = new ilCalendarAppointmentTemplate($fbdl_id);
3302  $app->setTranslationType(IL_CAL_TRANSLATION_SYSTEM);
3303  $app->setSubtitle("cal_exc_peer_review_deadline");
3304  $app->setTitle($this->getTitle());
3305  $app->setFullday(false);
3306  $app->setStart(new ilDateTime($this->getPeerReviewDeadline(), IL_CAL_UNIX));
3307 
3308  $apps[] = $app;
3309  }
3310 
3311  }
3312 
3313  include_once "Modules/Exercise/classes/class.ilObjExercise.php";
3314  $exc = new ilObjExercise($this->getExerciseId(), false);
3315 
3316  $ilAppEventHandler->raise('Modules/Exercise',
3317  $a_event.'Assignment',
3318  array(
3319  'object' => $exc,
3320  'obj_id' => $exc->getId(),
3321  'context_ids' => $context_ids,
3322  'appointments' => $apps));
3323  }
3324 
3325  public static function getAdoptableTeamAssignments($a_exercise_id, $a_exclude_ass_id = null, $a_user_id = null)
3326  {
3327  $res = array();
3328 
3329  $data = ilExAssignment::getAssignmentDataOfExercise($a_exercise_id);
3330  foreach($data as $row)
3331  {
3332  if($a_exclude_ass_id && $row["id"] == $a_exclude_ass_id)
3333  {
3334  continue;
3335  }
3336 
3337  if($row["type"] == ilExAssignment::TYPE_UPLOAD_TEAM)
3338  {
3339  $map = ilExAssignment::getAssignmentTeamMap($row["id"]);
3340 
3341  if($a_user_id && !array_key_exists($a_user_id, $map))
3342  {
3343  continue;
3344  }
3345 
3346  if(sizeof($map))
3347  {
3348  $user_team = null;
3349  if($a_user_id)
3350  {
3351  $user_team_id = $map[$a_user_id];
3352  $user_team = array();
3353  foreach($map as $user_id => $team_id)
3354  {
3355  if($user_id != $a_user_id &&
3356  $user_team_id == $team_id)
3357  {
3358  $user_team[] = $user_id;
3359  }
3360  }
3361  }
3362 
3363  if(!$a_user_id ||
3364  sizeof($user_team))
3365  {
3366  $res[$row["id"]] = array(
3367  "title" => $row["title"],
3368  "teams" => sizeof(array_flip($map)),
3369  );
3370 
3371  if($a_user_id)
3372  {
3373  $res[$row["id"]]["user_team"] = $user_team;
3374  }
3375  }
3376  }
3377  }
3378  }
3379 
3380  return ilUtil::sortArray($res, "title", "asc", false, true);
3381  }
3382 
3383  public function adoptTeams($a_source_ass_id, $a_user_id = null, $a_exc_ref_id = null)
3384  {
3385  $teams = array();
3386 
3387  $old_team = null;
3388  foreach(self::getAssignmentTeamMap($a_source_ass_id) as $user_id => $team_id)
3389  {
3390  $teams[$team_id][] = $user_id;
3391 
3392  if($a_user_id && $user_id == $a_user_id)
3393  {
3394  $old_team = $team_id;
3395  }
3396  }
3397 
3398  if($a_user_id)
3399  {
3400  // no existing team (in source) or user already in team (in current)
3401  if(!$old_team || $this->getTeamId($a_user_id))
3402  {
3403  return;
3404  }
3405  }
3406 
3407  $current_map = self::getAssignmentTeamMap($this->getId());
3408 
3409  foreach($teams as $team_id => $user_ids)
3410  {
3411  if(!$old_team || $team_id == $old_team)
3412  {
3413  // only not assigned users
3414  $missing = array();
3415  foreach($user_ids as $user_id)
3416  {
3417  if(!array_key_exists($user_id, $current_map))
3418  {
3419  $missing[] = $user_id;
3420  }
3421  }
3422 
3423  if(sizeof($missing))
3424  {
3425  // create new team
3426  $first = array_shift($missing);
3427  $team_id = $this->getTeamId($first, true);
3428 
3429  if($a_exc_ref_id)
3430  {
3431  // getTeamId() does NOT send notification
3432  $this->sendNotification($a_exc_ref_id, $first, "add");
3433  }
3434 
3435  foreach($missing as $user_id)
3436  {
3437  $this->addTeamMember($team_id, $user_id, $a_exc_ref_id);
3438  }
3439  }
3440  }
3441  }
3442  }
3443 }
3444 
3445 ?>