ba364f34449ed1e38e358ef14685c735b6bd15ac
[moodle.git] / mod / assignment / restorelib.php
1 <?php
2     //This php script contains all the stuff to backup/restore
3     //assignment mods
5     //This is the "graphical" structure of the assignment mod:
6     //
7     //                     assignment
8     //                    (CL,pk->id)
9     //                        |
10     //                        |
11     //                        |
12     //                 assignment_submisions
13     //           (UL,pk->id, fk->assignment,files)
14     //
15     // Meaning: pk->primary key field of the table
16     //          fk->foreign key to link with parent
17     //          nt->nested field (recursive data)
18     //          CL->course level info
19     //          UL->user level info
20     //          files->table may have files)
21     //
22     //-----------------------------------------------------------
24     //This function executes all the restore procedure about this mod
25     function assignment_restore_mods($mod,$restore) {
26         global $CFG, $DB;
28         $status = true;
30         //Get record from backup_ids
31         $data = backup_getid($restore->backup_unique_code,$mod->modtype,$mod->id);
33         if ($data) {
34             //Now get completed xmlized object
35             $info = $data->info;
36             //if necessary, write to restorelog and adjust date/time fields
37             if ($restore->course_startdateoffset) {
38                 restore_log_date_changes('Assignment', $restore, $info['MOD']['#'], array('TIMEDUE', 'TIMEAVAILABLE'));
39             }
40             //traverse_xmlize($info);                                                                     //Debug
41             //print_object ($GLOBALS['traverse_array']);                                                  //Debug
42             //$GLOBALS['traverse_array']="";                                                              //Debug
44             //Now, build the ASSIGNMENT record structure
45             $assignment->course = $restore->course_id;
46             $assignment->name = backup_todb($info['MOD']['#']['NAME']['0']['#']);
47             $assignment->intro = backup_todb($info['MOD']['#']['DESCRIPTION']['0']['#']);
48             $assignment->introformat = backup_todb($info['MOD']['#']['FORMAT']['0']['#']);
49             $assignment->resubmit = backup_todb($info['MOD']['#']['RESUBMIT']['0']['#']);
50             $assignment->preventlate = backup_todb($info['MOD']['#']['PREVENTLATE']['0']['#']);
51             $assignment->emailteachers = backup_todb($info['MOD']['#']['EMAILTEACHERS']['0']['#']);
52             $assignment->var1 = backup_todb($info['MOD']['#']['VAR1']['0']['#']);
53             $assignment->var2 = backup_todb($info['MOD']['#']['VAR2']['0']['#']);
54             $assignment->var3 = backup_todb($info['MOD']['#']['VAR3']['0']['#']);
55             $assignment->var4 = backup_todb($info['MOD']['#']['VAR4']['0']['#']);
56             $assignment->var5 = backup_todb($info['MOD']['#']['VAR5']['0']['#']);
57             $assignment->type = isset($info['MOD']['#']['TYPE']['0']['#'])?backup_todb($info['MOD']['#']['TYPE']['0']['#']):'';
58             $assignment->assignmenttype = backup_todb($info['MOD']['#']['ASSIGNMENTTYPE']['0']['#']);
59             $assignment->maxbytes = backup_todb($info['MOD']['#']['MAXBYTES']['0']['#']);
60             $assignment->timedue = backup_todb($info['MOD']['#']['TIMEDUE']['0']['#']);
61             $assignment->timeavailable = backup_todb($info['MOD']['#']['TIMEAVAILABLE']['0']['#']);
62             $assignment->grade = backup_todb($info['MOD']['#']['GRADE']['0']['#']);
63             $assignment->timemodified = backup_todb($info['MOD']['#']['TIMEMODIFIED']['0']['#']);
65             //We have to recode the grade field if it is <0 (scale)
66             if ($assignment->grade < 0) {
67                 $scale = backup_getid($restore->backup_unique_code,"scale",abs($assignment->grade));
68                 if ($scale) {
69                     $assignment->grade = -($scale->new_id);
70                 }
71             }
73             if (empty($assignment->assignmenttype)) {   /// Pre 1.5 assignment
74                 if ($assignment->type == 1) {
75                     $assignment->assignmenttype = 'uploadsingle';
76                 } else {
77                     $assignment->assignmenttype = 'offline';
78                 }
79             }
81             // skip restore of plugins that are not installed
82             static $plugins;
83             if (!isset($plugins)) {
84                 $plugins = array_keys(get_plugin_list('assignment'));
85             }
87             if (!in_array($assignment->assignmenttype, $plugins)) {
88                 if (!defined('RESTORE_SILENTLY')) {
89                     echo "<li><strong>".get_string("modulename","assignment")." \"".format_string($assignment->name,true)."\" - plugin '{$assignment->assignmenttype}' not available!</strong></li>";
90                 }
91                 return true; // do not fail the restore
92             }
94             //The structure is equal to the db, so insert the assignment
95             $newid = $DB->insert_record ("assignment",$assignment);
97             //Do some output
98             if (!defined('RESTORE_SILENTLY')) {
99                 echo "<li>".get_string("modulename","assignment")." \"".format_string($assignment->name,true)."\"</li>";
100             }
101             backup_flush(300);
103             if ($newid) {
104                 //We have the newid, update backup_ids
105                 backup_putid($restore->backup_unique_code,$mod->modtype,
106                              $mod->id, $newid);
108                 // load up the subtype and see if it wants anything further restored.
109                 $class = 'assignment_' . $assignment->assignmenttype;
110                 require_once($CFG->dirroot . '/mod/assignment/lib.php');
111                 require_once($CFG->dirroot . '/mod/assignment/type/' . $assignment->assignmenttype . '/assignment.class.php');
112                 call_user_func(array($class, 'restore_one_mod'), $info, $restore, $assignment);
114                 //Now check if want to restore user data and do it.
115                 if (restore_userdata_selected($restore,'assignment',$mod->id)) {
116                     //Restore assignmet_submissions
117                     $status = assignment_submissions_restore_mods($mod->id, $newid,$info,$restore) && $status;
118                     $status = assignment_submissions_restore_mods($mod->id, $newid,$info,$restore, $assignment) && $status;
119                 }
120             } else {
121                 $status = false;
122             }
123         } else {
124             $status = false;
125         }
127         return $status;
128     }
130     //This function restores the assignment_submissions
131     function assignment_submissions_restore_mods($old_assignment_id, $new_assignment_id,$info,$restore, $assignment) {
132         global $CFG, $DB;
134         $status = true;
136         //Get the submissions array - it might not be present
137         if (isset($info['MOD']['#']['SUBMISSIONS']['0']['#']['SUBMISSION'])) {
138             $submissions = $info['MOD']['#']['SUBMISSIONS']['0']['#']['SUBMISSION'];
139         } else {
140             $submissions = array();
141         }
143         //Iterate over submissions
144         for($i = 0; $i < sizeof($submissions); $i++) {
145             $sub_info = $submissions[$i];
146             //traverse_xmlize($sub_info);                                                                 //Debug
147             //print_object ($GLOBALS['traverse_array']);                                                  //Debug
148             //$GLOBALS['traverse_array']="";                                                              //Debug
150             //We'll need this later!!
151             $oldid = backup_todb($sub_info['#']['ID']['0']['#']);
152             $olduserid = backup_todb($sub_info['#']['USERID']['0']['#']);
154             //Now, build the ASSIGNMENT_SUBMISSIONS record structure
155             $submission->assignment = $new_assignment_id;
156             $submission->userid = backup_todb($sub_info['#']['USERID']['0']['#']);
157             $submission->timecreated = backup_todb($sub_info['#']['TIMECREATED']['0']['#']);
158             $submission->timemodified = backup_todb($sub_info['#']['TIMEMODIFIED']['0']['#']);
159             $submission->numfiles = backup_todb($sub_info['#']['NUMFILES']['0']['#']);
160             $submission->data1 = backup_todb($sub_info['#']['DATA1']['0']['#']);
161             $submission->data2 = backup_todb($sub_info['#']['DATA2']['0']['#']);
162             $submission->grade = backup_todb($sub_info['#']['GRADE']['0']['#']);
163             if (isset($sub_info['#']['COMMENT']['0']['#'])) {
164                 $submission->submissioncomment = backup_todb($sub_info['#']['COMMENT']['0']['#']);
165             } else {
166                 $submission->submissioncomment = backup_todb($sub_info['#']['SUBMISSIONCOMMENT']['0']['#']);
167             }
168             $submission->format = backup_todb($sub_info['#']['FORMAT']['0']['#']);
169             $submission->teacher = backup_todb($sub_info['#']['TEACHER']['0']['#']);
170             $submission->timemarked = backup_todb($sub_info['#']['TIMEMARKED']['0']['#']);
171             $submission->mailed = backup_todb($sub_info['#']['MAILED']['0']['#']);
173             //We have to recode the userid field
174             $user = backup_getid($restore->backup_unique_code,"user",$submission->userid);
175             if ($user) {
176                 $submission->userid = $user->new_id;
177             }
179             //We have to recode the teacher field
180             $user = backup_getid($restore->backup_unique_code,"user",$submission->teacher);
181             if ($user) {
182                 $submission->teacher = $user->new_id;
183             }
185             //The structure is equal to the db, so insert the assignment_submission
186             $newid = $DB->insert_record ("assignment_submissions",$submission);
188             //Do some output
189             if (($i+1) % 50 == 0) {
190                 if (!defined('RESTORE_SILENTLY')) {
191                     echo ".";
192                     if (($i+1) % 1000 == 0) {
193                         echo "<br />";
194                     }
195                 }
196                 backup_flush(300);
197             }
199             if ($newid) {
200                 //We have the newid, update backup_ids
201                 backup_putid($restore->backup_unique_code,"assignment_submission",$oldid,
202                              $newid);
204                 //Now copy moddata associated files
205                 $status = assignment_restore_files ($old_assignment_id, $new_assignment_id,
206                                                     $olduserid, $submission->userid, $restore);
208                 $submission->id = $newid;
209                 $class = 'assignment_' . $assignment->assignmenttype;
210                 require_once($CFG->dirroot . '/mod/assignment/lib.php');
211                 require_once($CFG->dirroot . '/mod/assignment/type/' . $assignment->assignmenttype . '/assignment.class.php');
212                 call_user_func(array($class, 'restore_one_submission'), $sub_info, $restore, $assignment, $submission);
213             } else {
214                 $status = false;
215             }
216         }
218         return $status;
219     }
221     //This function copies the assignment related info from backup temp dir to course moddata folder,
222     //creating it if needed and recoding everything (assignment id and user id)
223     function assignment_restore_files ($oldassid, $newassid, $olduserid, $newuserid, $restore) {
225         global $CFG;
227         $status = true;
228         $todo = false;
229         $moddata_path = "";
230         $assignment_path = "";
231         $temp_path = "";
233         //First, we check to "course_id" exists and create is as necessary
234         //in CFG->dataroot
235         $dest_dir = $CFG->dataroot."/".$restore->course_id;
236         $status = check_dir_exists($dest_dir,true);
238         //Now, locate course's moddata directory
239         $moddata_path = $CFG->dataroot."/".$restore->course_id."/".$CFG->moddata;
241         //Check it exists and create it
242         $status = check_dir_exists($moddata_path,true);
244         //Now, locate assignment directory
245         if ($status) {
246             $assignment_path = $moddata_path."/assignment";
247             //Check it exists and create it
248             $status = check_dir_exists($assignment_path,true);
249         }
251         //Now locate the temp dir we are gong to restore
252         if ($status) {
253             $temp_path = $CFG->dataroot."/temp/backup/".$restore->backup_unique_code.
254                          "/moddata/assignment/".$oldassid."/".$olduserid;
255             //Check it exists
256             if (is_dir($temp_path)) {
257                 $todo = true;
258             }
259         }
261         //If todo, we create the neccesary dirs in course moddata/assignment
262         if ($status and $todo) {
263             //First this assignment id
264             $this_assignment_path = $assignment_path."/".$newassid;
265             $status = check_dir_exists($this_assignment_path,true);
266             //Now this user id
267             $user_assignment_path = $this_assignment_path."/".$newuserid;
268             //And now, copy temp_path to user_assignment_path
269             $status = backup_copy_file($temp_path, $user_assignment_path);
270         }
272         return $status;
273     }
275     //Return a content decoded to support interactivities linking. Every module
276     //should have its own. They are called automatically from
277     //assignment_decode_content_links_caller() function in each module
278     //in the restore process
279     function assignment_decode_content_links ($content,$restore) {
281         global $CFG;
283         $result = $content;
285         //Link to the list of assignments
287         $searchstring='/\$@(ASSIGNMENTINDEX)\*([0-9]+)@\$/';
288         //We look for it
289         preg_match_all($searchstring,$content,$foundset);
290         //If found, then we are going to look for its new id (in backup tables)
291         if ($foundset[0]) {
292             //print_object($foundset);                                     //Debug
293             //Iterate over foundset[2]. They are the old_ids
294             foreach($foundset[2] as $old_id) {
295                 //We get the needed variables here (course id)
296                 $rec = backup_getid($restore->backup_unique_code,"course",$old_id);
297                 //Personalize the searchstring
298                 $searchstring='/\$@(ASSIGNMENTINDEX)\*('.$old_id.')@\$/';
299                 //If it is a link to this course, update the link to its new location
300                 if($rec->new_id) {
301                     //Now replace it
302                     $result= preg_replace($searchstring,$CFG->wwwroot.'/mod/assignment/index.php?id='.$rec->new_id,$result);
303                 } else {
304                     //It's a foreign link so leave it as original
305                     $result= preg_replace($searchstring,$restore->original_wwwroot.'/mod/assignment/index.php?id='.$old_id,$result);
306                 }
307             }
308         }
310         //Link to assignment view by moduleid
312         $searchstring='/\$@(ASSIGNMENTVIEWBYID)\*([0-9]+)@\$/';
313         //We look for it
314         preg_match_all($searchstring,$result,$foundset);
315         //If found, then we are going to look for its new id (in backup tables)
316         if ($foundset[0]) {
317             //print_object($foundset);                                     //Debug
318             //Iterate over foundset[2]. They are the old_ids
319             foreach($foundset[2] as $old_id) {
320                 //We get the needed variables here (course_modules id)
321                 $rec = backup_getid($restore->backup_unique_code,"course_modules",$old_id);
322                 //Personalize the searchstring
323                 $searchstring='/\$@(ASSIGNMENTVIEWBYID)\*('.$old_id.')@\$/';
324                 //If it is a link to this course, update the link to its new location
325                 if($rec->new_id) {
326                     //Now replace it
327                     $result= preg_replace($searchstring,$CFG->wwwroot.'/mod/assignment/view.php?id='.$rec->new_id,$result);
328                 } else {
329                     //It's a foreign link so leave it as original
330                     $result= preg_replace($searchstring,$restore->original_wwwroot.'/mod/assignment/view.php?id='.$old_id,$result);
331                 }
332             }
333         }
335         return $result;
336     }
338     //This function makes all the necessary calls to xxxx_decode_content_links()
339     //function in each module, passing them the desired contents to be decoded
340     //from backup format to destination site/course in order to mantain inter-activities
341     //working in the backup/restore process. It's called from restore_decode_content_links()
342     //function in restore process
343     function assignment_decode_content_links_caller($restore) {
344         global $CFG, $DB;
345         $status = true;
347         if ($assignments = $DB->get_records('assignment', array('course'=>$restore->course_id), '', "id,description")) {
348             //Iterate over each assignment->description
349             $i = 0;   //Counter to send some output to the browser to avoid timeouts
350             foreach ($assignments as $assignment) {
351                 //Increment counter
352                 $i++;
353                 $content = $assignment->description;
354                 $result = restore_decode_content_links_worker($content,$restore);
355                 if ($result != $content) {
356                     //Update record
357                     $assignment->description = $result;
358                     $status = $DB->update_record("assignment",$assignment);
359                     if (debugging()) {
360                         if (!defined('RESTORE_SILENTLY')) {
361                             echo '<br /><hr />'.s($content).'<br />changed to<br />'.s($result).'<hr /><br />';
362                         }
363                     }
364                 }
365                 //Do some output
366                 if (($i+1) % 5 == 0) {
367                     if (!defined('RESTORE_SILENTLY')) {
368                         echo ".";
369                         if (($i+1) % 100 == 0) {
370                             echo "<br />";
371                         }
372                     }
373                     backup_flush(300);
374                 }
375             }
376         }
377         return $status;
378     }
380     //This function converts texts in FORMAT_WIKI to FORMAT_MARKDOWN for
381     //some texts in the module
382     function assignment_restore_wiki2markdown ($restore) {
383         global $CFG, $DB;
385         $status = true;
387         //Convert assignment->description
388         if ($records = $DB->get_records_sql ("SELECT a.id, a.intro, a.introformat
389                                                 FROM {assignment} a, {backup_ids} b
390                                                WHERE a.course = ? AND
391                                                a.format = ".FORMAT_WIKI. " AND
392                                                b.backup_code = ? AND
393                                                b.table_name = 'assignment' AND
394                                                b.new_id = a.id", array($restore->course_id, $restore->backup_unique_code))) {
395             foreach ($records as $record) {
396                 //Rebuild wiki links
397                 $record->intro = restore_decode_wiki_content($record->intro, $restore);
398                 //Convert to Markdown
399                 $wtm = new WikiToMarkdown();
400                 $record->intro = $wtm->convert($record->intro, $restore->course_id);
401                 $record->introformat = FORMAT_MARKDOWN;
402                 $status = $DB->update_record('assignment', $record);
403                 //Do some output
404                 $i++;
405                 if (($i+1) % 1 == 0) {
406                     if (!defined('RESTORE_SILENTLY')) {
407                         echo ".";
408                         if (($i+1) % 20 == 0) {
409                             echo "<br />";
410                         }
411                     }
412                     backup_flush(300);
413                 }
414             }
416         }
417         return $status;
418     }
420     //This function returns a log record with all the necessay transformations
421     //done. It's used by restore_log_module() to restore modules log.
422     function assignment_restore_logs($restore,$log) {
424         $status = false;
426         //Depending of the action, we recode different things
427         switch ($log->action) {
428         case "add":
429             if ($log->cmid) {
430                 //Get the new_id of the module (to recode the info field)
431                 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
432                 if ($mod) {
433                     $log->url = "view.php?id=".$log->cmid;
434                     $log->info = $mod->new_id;
435                     $status = true;
436                 }
437             }
438             break;
439         case "update":
440             if ($log->cmid) {
441                 //Get the new_id of the module (to recode the info field)
442                 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
443                 if ($mod) {
444                     $log->url = "view.php?id=".$log->cmid;
445                     $log->info = $mod->new_id;
446                     $status = true;
447                 }
448             }
449             break;
450         case "view":
451             if ($log->cmid) {
452                 //Get the new_id of the module (to recode the info field)
453                 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
454                 if ($mod) {
455                     $log->url = "view.php?id=".$log->cmid;
456                     $log->info = $mod->new_id;
457                     $status = true;
458                 }
459             }
460             break;
461         case "view all":
462             $log->url = "index.php?id=".$log->course;
463             $status = true;
464             break;
465         case "upload":
466             if ($log->cmid) {
467                 //Get the new_id of the module (to recode the info field)
468                 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
469                 if ($mod) {
470                     $log->url = "view.php?a=".$mod->new_id;
471                     $log->info = $mod->new_id;
472                     $status = true;
473                 }
474             }
475             break;
476         case "view submission":
477             if ($log->cmid) {
478                 //Get the new_id of the module (to recode the info field)
479                 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
480                 if ($mod) {
481                     $log->url = "submissions.php?id=".$mod->new_id;
482                     $log->info = $mod->new_id;
483                     $status = true;
484                 }
485             }
486             break;
487         case "update grades":
488             if ($log->cmid) {
489                 //Extract the assignment id from the url field
490                 $assid = substr(strrchr($log->url,"="),1);
491                 //Get the new_id of the module (to recode the info field)
492                 $mod = backup_getid($restore->backup_unique_code,$log->module,$assid);
493                 if ($mod) {
494                     $log->url = "submissions.php?id=".$mod->new_id;
495                     $status = true;
496                 }
497             }
498             break;
499         default:
500             if (!defined('RESTORE_SILENTLY')) {
501                 echo "action (".$log->module."-".$log->action.") unknown. Not restored<br />";                 //Debug
502             }
503             break;
504         }
506         if ($status) {
507             $status = $log;
508         }
509         return $status;
510     }