ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilExerciseManagementCollectFilesJob.php
Go to the documentation of this file.
1<?php
8
9/* Copyright (c) 1998-2018 ILIAS open source, Extended GPL, see docs/LICENSE */
10
18{
22 private $logger = null;
28 protected $assignment;
29 protected $user_id;
30 protected $exercise_id;
32 protected $temp_dir;
33 protected $lng;
34 protected $sanitized_title; //sanitized file name/sheet title
35 protected $excel; //ilExcel
36 protected $criteria_items; //array
37 protected $title_columns;
38 protected $ass_types_with_files; //TODO will be deprecated when use the new assignment type interface
39 protected $participant_id;
40
41 const FBK_DIRECTORY = "Feedback_files";
42 const LINK_COLOR = "0,0,255";
43 const BG_COLOR = "255,255,255";
44 //Column number incremented in ilExcel
51
55 public function __construct()
56 {
57 global $DIC;
58 $this->lng = $DIC->language();
59 $this->lng->loadLanguageModule('exc');
60 //TODO will be deprecated when use the new assignment type interface
61 $this->ass_types_with_files = array(
66 );
67 $this->logger = $DIC->logger()->exc();
68 }
69
73 public function getInputTypes()
74 {
75 return
76 [
77 new SingleType(IntegerValue::class),
78 new SingleType(IntegerValue::class),
79 new SingleType(IntegerValue::class),
80 new SingleType(IntegerValue::class),
81 new SingleType(IntegerValue::class)
82 ];
83 }
84
88 public function getOutputType()
89 {
90 return new SingleType(StringValue::class);
91 }
92
93 public function isStateless()
94 {
95 return true;
96 }
97
104 public function run(array $input, Observer $observer)
105 {
106 $this->exercise_id = $input[0]->getValue();
107 $this->exercise_ref_id = $input[1]->getValue();
108 $assignment_id = $input[2]->getValue();
109 $participant_id = $input[3]->getValue();
110 $this->user_id = $input[4]->getValue();
111
112 //if we have assignment
113 if ($assignment_id > 0) {
114 $this->collectAssignmentData($assignment_id);
115 $final_directory = $this->target_directory;
116 }
117
118 if ($participant_id > 0) {
119 $this->participant_id = $participant_id;
120 $assignments = ilExAssignment::getInstancesByExercise($this->exercise_id);
121 foreach ($assignments as $assignment) {
122 $this->collectAssignmentData($assignment->getId());
123 }
124 $final_directory = $this->temp_dir . DIRECTORY_SEPARATOR . ilExSubmission::getDirectoryNameFromUserData($participant_id);
125 }
126
127 $out = new StringValue();
128 $out->setValue($final_directory);
129 return $out;
130 }
131
138 public function copyFileToSubDirectory($a_directory, $a_file)
139 {
140 $dir = $this->target_directory . "/" . $a_directory;
141
142 if (!is_dir($dir)) {
144 }
145
146 copy($a_file, $dir . "/" . basename($a_file));
147
148 /*global $DIC;
149 $fs = $DIC->filesystem();
150
151 $fs->storage()->copy($a_file, $this->temp_dir."/".basename($a_file));*/
152 }
153
158 {
159 return 30;
160 }
161
165 protected function addColumnTitles()
166 {
167 $col = 0;
168 foreach ($this->title_columns as $title) {
169 $this->excel->setCell(1, $col, $title);
170 $col++;
171 }
172 }
173
178 protected function createUniqueTempDirectory()
179 {
180 $this->temp_dir = ilUtil::ilTempnam();
181 ilUtil::makeDirParents($this->temp_dir);
182 }
183
187 protected function createTargetDirectory()
188 {
189 $path = $this->temp_dir . DIRECTORY_SEPARATOR;
190 if ($this->participant_id > 0) {
191 $user_dir = ilExSubmission::getDirectoryNameFromUserData($this->participant_id);
192 $path .= $user_dir . DIRECTORY_SEPARATOR;
193 }
194 $this->target_directory = $path . $this->sanitized_title;
195
196 ilUtil::makeDirParents($this->target_directory);
197 }
201 protected function createSubmissionsDirectory()
202 {
203 $this->logger->debug("lang key => " . $this->lng->getLangKey());
204 $this->submissions_directory = $this->target_directory . DIRECTORY_SEPARATOR . $this->lng->txt("exc_ass_submission_zip");
205 ilUtil::createDirectory($this->submissions_directory);
206 }
207
213 public function collectSubmissionFiles()
214 {
215 $members = array();
216
217 $exercise = new ilObjExercise($this->exercise_id, false);
218
219 if ($this->participant_id > 0) {
220 $exc_members_id = array($this->participant_id);
221 } else {
222 $exc_members_id = $exercise->members_obj->getMembers();
223 }
224
225 $filter = new ilExerciseMembersFilter($this->exercise_ref_id, $exc_members_id, $this->user_id);
226 $exc_members_id = $filter->filterParticipantsByAccess();
227
228 foreach ($exc_members_id as $member_id) {
229 $submission = new ilExSubmission($this->assignment, $member_id);
230 $submission->updateTutorDownloadTime();
231
232 // get member object (ilObjUser)
233 if (ilObject::_exists($member_id)) {
234 // adding file metadata
235 foreach ($submission->getFiles() as $file) {
236 $members[$file["user_id"]]["files"][$file["returned_id"]] = $file;
237 }
238
239 $tmp_obj = &ilObjectFactory::getInstanceByObjId($member_id);
240 $members[$member_id]["name"] = $tmp_obj->getFirstname() . " " . $tmp_obj->getLastname();
241 unset($tmp_obj);
242 }
243 }
244
245 ilExSubmission::downloadAllAssignmentFiles($this->assignment, $members, $this->submissions_directory);
246 }
247
253 protected function isExcelNeeded($a_ass_type, $a_has_fbk)
254 {
255 if ($a_ass_type == ilExAssignment::TYPE_TEXT) {
256 return true;
257 } elseif ($a_has_fbk && $a_ass_type != ilExAssignment::TYPE_UPLOAD_TEAM) {
258 return true;
259 }
260 return false;
261 }
262
270 protected function addCriteriaToExcel($feedback_giver, $participant_id, $row, $col)
271 {
272 $submission = new ilExSubmission($this->assignment, $participant_id);
273
274 //Possible TODO: This getPeerReviewValues doesn't return always the same array structure then the client classes have
275 //to deal with this. Use only one data structure will avoid this extra work.
276 //values can be [19] => "blablablab" or ["text"] => "blablabla"
277 $values = $submission->getPeerReview()->getPeerReviewValues($feedback_giver, $participant_id);
278
279 foreach ($this->criteria_items as $item) {
280 $col++;
281
282 //Criteria without catalog doesn't have ID nor TITLE. The criteria instance is given via "type" ilExcCriteria::getInstanceByType
283 $crit_id = $item->getId();
284 $crit_type = $item->getType();
285 $crit_title = $item->getTitle();
286 if ($crit_title == "") {
287 $crit_title = $item->getTranslatedType();
288 }
289
290 if (!in_array($crit_title, $this->title_columns)) {
291 $this->title_columns[] = $crit_title;
292 }
293 switch ($crit_type) {
294 case 'bool':
295 if ($values[$crit_id] == 1) {
296 $this->excel->setCell($row, $col, $this->lng->txt("yes"));
297 } elseif ($values[$crit_id] == -1) {
298 $this->excel->setCell($row, $col, $this->lng->txt("no"));
299 }
300 break;
301 case 'rating':
302 /*
303 * Get the rating data from the DB in the current less expensive way.
304 * assignment_id -> used in il_rating.obj_id
305 * object type as string -> used in il_rating.obj_type
306 * participant id -> il_rating.sub_obj_id
307 * "peer_" + criteria_id -> il_rating.sub_obj_type (peer or e.g. peer_12)
308 * peer id -> il_rating.user_id
309 */
310 // Possible TODO: refactor ilExAssignment->getPeerReviewCriteriaCatalogueItems somehow to avoid client
311 // classes to deal with ilExCriteria instances with persistence (by id) or instances on the fly (by type)
312 $sub_obj_type = "peer";
313 if ($crit_id) {
314 $sub_obj_type .= "_" . $crit_id;
315 }
317 $this->assignment->getId(),
318 'ass',
320 $sub_obj_type,
321 $feedback_giver
322 );
323 if ($rating_int = round((int) $rating)) {
324 $this->excel->setCell($row, $col, $rating_int);
325 }
326 break;
327 case 'text':
328 //again another check for criteria id (if instantiated via type)
329 if ($crit_id) {
330 $this->excel->setCell($row, $col, $values[$crit_id]);
331 } else {
332 $this->excel->setCell($row, $col, $values['text']);
333 }
334 break;
335 case 'file':
336 if ($crit_id) {
337 $crit_file_obj = ilExcCriteriaFile::getInstanceById($crit_id);
338 } else {
339 $crit_file_obj = ilExcCriteriaFile::getInstanceByType($crit_type);
340 }
341 $crit_file_obj->setPeerReviewContext($this->assignment, $feedback_giver, $participant_id);
342 $files = $crit_file_obj->getFiles();
343
344 $extra_crit_column = 0;
345 foreach ($files as $file) {
346 if ($extra_crit_column) {
347 $this->title_columns[] = $crit_title . "_" . $extra_crit_column;
348 }
349 $extra_crit_column++;
350 $this->copyFileToSubDirectory(self::FBK_DIRECTORY, $file);
351 $this->excel->setCell($row, $col, "./" . self::FBK_DIRECTORY . DIRECTORY_SEPARATOR . basename($file));
352 $this->excel->addLink($row, $col, './' . self::FBK_DIRECTORY . DIRECTORY_SEPARATOR . basename($file));
353 $this->excel->setColors($this->excel->getCoordByColumnAndRow($col, $row), self::BG_COLOR, self::LINK_COLOR);
354 }
355 break;
356 }
357 }
358 }
359
367 public function getExtraColumnsForSubmissionFiles($a_obj_id, $a_ass_id)
368 {
369 global $DIC;
370 $ilDB = $DIC->database();
371
372 $and = "";
373 if ($this->participant_id > 0) {
374 $and = " AND user_id = " . $this->participant_id;
375 }
376
377 $query = "SELECT MAX(max_num) AS max" .
378 " FROM (SELECT COUNT(user_id) AS max_num FROM exc_returned" .
379 " WHERE obj_id=" . $a_obj_id . ". AND ass_id=" . $a_ass_id . $and . " AND mimetype IS NOT NULL" .
380 " GROUP BY user_id) AS COUNTS";
381
382 $set = $ilDB->query($query);
383 $row = $ilDB->fetchAssoc($set);
384 return $row['max'];
385 }
386
394 public function addLink($a_row, $a_col, $a_submission_file)
395 {
396 $user_id = $a_submission_file['user_id'];
398
399 $filepath = './' . $this->lng->txt("exc_ass_submission_zip") . DIRECTORY_SEPARATOR . $targetdir . DIRECTORY_SEPARATOR;
400 switch ($this->assignment->getType()) {
402 $filepath .= $a_submission_file['filetitle'];
403 break;
404
406 include_once "Services/PersonalWorkspace/classes/class.ilWorkspaceTree.php";
407 $wsp_tree = new ilWorkspaceTree($user_id);
408 // #12939
409 if (!$wsp_tree->getRootId()) {
410 $wsp_tree->createTreeForUser($user_id);
411 }
412 $node = $wsp_tree->getNodeData((int) $a_submission_file['filetitle']);
413 $filepath .= "blog_" . $node['obj_id'] . DIRECTORY_SEPARATOR . "index.html";
414 break;
415
417 $filepath .= "prt_" . $a_submission_file['filetitle'] . DIRECTORY_SEPARATOR . "index.html";
418 break;
419
420 default:
421 $filepath = "";
422 }
423 $this->excel->addLink($a_row, $a_col, $filepath);
424 }
425
426 protected function collectAssignmentData($assignment_id)
427 {
428 $ass_has_feedback = false;
429 $ass_has_criteria = false;
430
431 //assignment object
432 $this->assignment = new ilExAssignment($assignment_id);
433 $assignment_type = $this->assignment->getType();
434
435 //Sanitized title for excel file and target directory.
436 $this->sanitized_title = ilUtil::getASCIIFilename($this->assignment->getTitle());
437
438 // directories
439 if (!isset($this->temp_dir)) {
441 }
442 $this->createTargetDirectory();
443
444 //Collect submission files if needed by assignment type.
445 if (in_array($assignment_type, $this->ass_types_with_files)) {
447 $this->collectSubmissionFiles();
448 }
449
450 if ($this->assignment->getPeerReview()) {
451 $ass_has_feedback = true;
452 //obj to get the reviews in the foreach below.
453 $peer_review = new ilExPeerReview($this->assignment);
454 //default start column for revisions.
455 $first_excel_column_for_review = self::FIRST_DEFAULT_REVIEW_COLUMN;
456 }
457
463 if ($this->isExcelNeeded($assignment_type, $ass_has_feedback)) {
464 // PhpSpreadsheet object
465 include_once "./Services/Excel/classes/class.ilExcel.php";
466 $this->excel = new ilExcel();
467
468 //Excel sheet title
469 $this->excel->addSheet($this->sanitized_title);
470
471 //add common excel Columns
472 #25585
473 $this->title_columns = array(
474 $this->lng->txt('lastname'),
475 $this->lng->txt('firstname'),
476 $this->lng->txt('login'),
477 $this->lng->txt('exc_last_submission')
478 );
479 switch ($assignment_type) {
481 $this->title_columns[] = $this->lng->txt("exc_submission_text");
482 break;
484 $num_columns_submission = $this->getExtraColumnsForSubmissionFiles($this->exercise_id, $assignment_id);
485 if ($num_columns_submission > 1) {
486 for ($i = 1; $i <= $num_columns_submission; $i++) {
487 $this->title_columns[] = $this->lng->txt("exc_submission_file") . " " . $i;
488 }
489 } else {
490 $this->title_columns[] = $this->lng->txt("exc_submission_file");
491 }
492
493 $first_excel_column_for_review += $num_columns_submission - 1;
494 break;
495 default:
496 $this->title_columns[] = $this->lng->txt("exc_submission");
497 break;
498 }
499 if ($ass_has_feedback) {
500 $this->title_columns[] = $this->lng->txt("exc_peer_review_giver");
501 $this->title_columns[] = $this->lng->txt('exc_last_submission');
502 }
503
504 //criteria
505 //Notice:getPeerReviewCriteriaCatalogueItems can return just an empty instance without data.
506 if ($this->criteria_items = $this->assignment->getPeerReviewCriteriaCatalogueItems()) {
507 $ass_has_criteria = true;
508 }
509
510 if ($this->participant_id > 0) {
511 $participants = array($this->participant_id);
512 } else {
513 $participants = $this->getAssignmentMembersIds();
514 }
515
516 $filter = new ilExerciseMembersFilter($this->exercise_ref_id, $participants, $this->user_id);
517 $participants = $filter->filterParticipantsByAccess();
518
519 //SET THE ROW AT SECOND POSITION TO START ENTERING VALUES BELOW THE TITLE.
520 $row = 2;
521 // Fill the excel
522 foreach ($participants as $participant_id) {
523 $submission = new ilExSubmission($this->assignment, $participant_id);
524 $submission_files = $submission->getFiles();
525
526 if ($submission_files) {
527 $participant_name = ilObjUser::_lookupName($participant_id);
528 $this->excel->setCell($row, self::PARTICIPANT_LASTNAME_COLUMN, $participant_name['lastname']);
529 $this->excel->setCell($row, self::PARTICIPANT_FIRSTNAME_COLUMN, $participant_name['firstname']);
530 $this->excel->setCell($row, self::PARTICIPANT_LOGIN_COLUMN, $participant_name['login']);
531
532 //Get the submission Text
533 if (!in_array($assignment_type, $this->ass_types_with_files)) {
534 foreach ($submission_files as $submission_file) {
535 $this->excel->setCell($row, self::SUBMISSION_DATE_COLUMN, $submission_file['timestamp']);
536 $this->excel->setCell($row, self::FIRST_DEFAULT_SUBMIT_COLUMN, $submission_file['atext']);
537 }
538 } else {
540 foreach ($submission_files as $submission_file) {
541 $this->excel->setCell($row, self::SUBMISSION_DATE_COLUMN, $submission_file['timestamp']);
542
543 if ($assignment_type == ilExAssignment::TYPE_PORTFOLIO || $assignment_type == ilExAssignment::TYPE_BLOG) {
544 $this->excel->setCell($row, $col, $this->lng->txt("open"));
545 } else {
546 $this->excel->setCell($row, $col, $submission_file['filetitle']);
547 }
548 $this->excel->setColors($this->excel->getCoordByColumnAndRow($col + 1, $row), self::BG_COLOR, self::LINK_COLOR);
549 $this->addLink($row, $col, $submission_file);
550 $col++; //does not affect blogs and portfolios.
551 }
552 }
553
554 if ($ass_has_feedback) {
555 if ($col < $first_excel_column_for_review) {
556 $col = $first_excel_column_for_review;
557 }
558 $reviews = $peer_review->getPeerReviewsByPeerId($participant_id);
559
560 //extra lines
561 $current_review_row = 0;
562 foreach ($reviews as $review) {
563 //not all reviews are done, we check it via date of review.
564 if ($review['tstamp']) {
565 $current_review_row++;
566 if ($current_review_row > 1) {
567 for ($i = 0; $i < $first_excel_column_for_review; $i++) {
568 $cell_to_copy = $this->excel->getCell($row, $i);
569 // $i-1 because ilExcel setCell increments the column by 1
570 $this->excel->setCell($row + 1, $i - 1, $cell_to_copy);
571 if ($i > self::FIRST_DEFAULT_SUBMIT_COLUMN) {
572 $this->excel->setColors($this->excel->getCoordByColumnAndRow($i, $row + 1), self::BG_COLOR, self::LINK_COLOR);
573 }
574 }
575 ++$row;
576 }
577
578 $feedback_giver = $review['giver_id']; // user who made the review.
579
580 $feedback_giver_name = ilObjUser::_lookupName($feedback_giver);
581
582 $this->excel->setCell(
583 $row,
584 $col,
585 $feedback_giver_name['lastname'] . ", " . $feedback_giver_name['firstname'] . " [" . $feedback_giver_name['login'] . "]"
586 );
587
588 $this->excel->setCell($row, $col + 1, $review['tstamp']);
589
590 if ($ass_has_criteria) {
591 $this->addCriteriaToExcel($feedback_giver, $participant_id, $row, $col + 1);
592 }
593 }
594 }
595 }
596
597 $row++;
598 }
599 }
600
601 $this->addColumnTitles();
602 $this->excel->writeToFile($this->target_directory . "/" . $this->sanitized_title);
603 }
604 }
605
606 // get ONLY the members ids for this assignment
607 public function getAssignmentMembersIds()
608 {
609 global $DIC;
610
611 $ilDB = $DIC->database();
612 $members = array();
613
614 $set = $ilDB->query("SELECT usr_id" .
615 " FROM exc_mem_ass_status" .
616 " WHERE ass_id = " . $ilDB->quote($this->assignment->getId(), "integer"));
617
618 while ($rec = $ilDB->fetchAssoc($set)) {
619 $members[] = $rec['usr_id'];
620 }
621
622 return $members;
623 }
624}
$path
Definition: aliased.php:25
An exception for terminatinating execution or to throw for unit testing.
Exercise assignment.
static getInstancesByExercise($a_exc_id)
Exercise peer review.
Exercise submission //TODO: This class has to much static methods related to delivered "files".
static downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members, $to_path)
Download all submitted files of an assignment (all user)
static getDirectoryNameFromUserData($a_user_id)
static getInstanceById($a_id)
static getInstanceByType($a_type)
copyFileToSubDirectory($a_directory, $a_file)
Copy a file in the Feedback_files directory TODO use the new filesystem.
run(array $input, Observer $observer)
run the job
addLink($a_row, $a_col, $a_submission_file)
Mapping the links to use them on the excel.
collectSubmissionFiles()
Store the zip file which contains all submission files in the target directory.
getExpectedTimeOfTaskInSeconds()
int the amount of seconds this task usually taskes. If your task-duration scales with the the amount ...
getExtraColumnsForSubmissionFiles($a_obj_id, $a_ass_id)
Get the number of max amount of files submitted by a single user in the assignment.
createTargetDirectory()
Create the directory with the assignment title.
createSubmissionsDirectory()
Create the directory with the assignment title.
addCriteriaToExcel($feedback_giver, $participant_id, $row, $col)
Add criteria data to the excel.
Class ilExerciseMembersFilter.
Class ilObjExercise.
static _lookupName($a_user_id)
lookup user name
static getInstanceByObjId($a_obj_id, $stop_on_error=true)
get an instance of an Ilias object by object id
static _exists($a_id, $a_reference=false, $a_type=null)
checks if an object exists in object_data@access public
static getRatingForUserAndObject( $a_obj_id, $a_obj_type, $a_sub_obj_id, $a_sub_obj_type, $a_user_id, $a_category_id=null)
Get rating for a user and an object.
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static createDirectory($a_dir, $a_mod=0755)
create directory
Tree handler for personal workspace.
$i
Definition: disco.tpl.php:19
$files
Definition: metarefresh.php:49
$row
$query
global $DIC
Definition: saml.php:7
global $ilDB
$values