]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/protected/Web/Pages/RestoreWizard.php
baculum: New reworked restore wizard
[bacula/bacula] / gui / baculum / protected / Web / Pages / RestoreWizard.php
1 <?php
2 /*
3  * Bacula(R) - The Network Backup Solution
4  * Baculum   - Bacula web interface
5  *
6  * Copyright (C) 2013-2017 Kern Sibbald
7  *
8  * The main author of Baculum is Marcin Haba.
9  * The original author of Bacula is Kern Sibbald, with contributions
10  * from many others, a complete list can be found in the file AUTHORS.
11  *
12  * You may use this file and others of this release according to the
13  * license defined in the LICENSE file, which includes the Affero General
14  * Public License, v3.0 ("AGPLv3") and some additional permissions and
15  * terms pursuant to its AGPLv3 Section 7.
16  *
17  * This notice must be preserved when any source code is
18  * conveyed and/or propagated.
19  *
20  * Bacula(R) is a registered trademark of Kern Sibbald.
21  */
22
23 Prado::using('Application.Web.Class.BaculumWebPage'); 
24 Prado::using('System.Exceptions.TException');
25 Prado::using('System.Web.UI.WebControls.TWizard');
26 Prado::using('System.Web.UI.WebControls.TDataGrid');
27 Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
28 Prado::using('System.Web.UI.ActiveControls.TActiveImageButton');
29 Prado::using('System.Web.UI.ActiveControls.TDropContainer');
30 Prado::using('System.Web.UI.ActiveControls.TDraggable');
31 Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid');
32 Prado::using('System.Web.UI.ActiveControls.TCallback');
33 Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
34
35 class RestoreWizard extends BaculumWebPage
36 {
37         /**
38          * Job levels allowed to restore.
39          */
40
41         private $joblevel = array('F', 'I', 'D');
42         /**
43          * Job statuses allowed to restore.
44          */
45         private $jobstatus = array('T', 'W', 'A', 'E', 'e', 'f');
46
47         /**
48          * File browser special directories.
49          */
50         private $browser_root_dir = array('name' => '.', 'type' => 'dir', 'fileid' => null);
51         private $browser_up_dir = array('name' => '..', 'type' => 'dir');
52
53         /**
54          * Used to provide in template selected by user single jobid to restore.
55          */
56         public $restore_single_jobid;
57
58         /**
59          * Stores file relocation option. Used in template.
60          */
61         public $file_relocation_opt;
62
63         /**
64          * FIle browser elements for which 'Add' button is unavailable.
65          */
66         public $excluded_elements_from_add = array('.', '..');
67
68         /**
69          * Prefix for Bvfs path.
70          */
71         const BVFS_PATH_PREFIX = 'b2';
72
73         public function onInit($param) {
74                 parent::onInit($param);
75                 if(!$this->IsPostBack && !$this->IsCallBack) {
76                         $this->resetWizard();
77                         $this->loadBackupClients();
78                 }
79         }
80
81         /**
82          * Wizard next button callback actions.
83          *
84          * @param TWizard $sender sender object
85          * @param TWizardNavigationEventParameter $param sender parameters
86          * @return none
87          */
88         public function wizardNext($sender, $param) {
89                 if ($param->CurrentStepIndex === 0) {
90                         $this->loadBackupsForClient();
91                         $this->loadGroupBackupToRestore();
92                         $this->loadGroupFileSetToRestore();
93                         $this->loadRestoreClients();
94                         if (isset($_SESSION['restore_single_jobid'])) {
95                                 $this->restore_single_jobid = $_SESSION['restore_single_jobid'];
96                         }
97                 } elseif ($param->CurrentStepIndex === 1) {
98                         if ($this->Request->contains('backup_to_restore')) {
99                                 $_SESSION['restore_single_jobid'] = $this->Request['backup_to_restore'];
100                         }
101                         $this->setFileVersions();
102                         $this->loadSelectedFiles();
103                         $this->loadFileVersions();
104                         $this->goToPath();
105                 } elseif ($param->CurrentStepIndex === 2) {
106                         $this->loadRequiredVolumes();
107                 } elseif ($param->CurrentStepIndex === 3) {
108                         if (isset($_SESSION['file_relocation'])) {
109                                 $this->file_relocation_opt = $_SESSION['file_relocation'];
110                         }
111                 } elseif ($param->CurrentStepIndex === 4) {
112                         if ($this->Request->contains('file_relocation')) {
113                                 $_SESSION['file_relocation'] = $this->Request['file_relocation'];
114                         }
115                         $this->file_relocation_opt = $_SESSION['file_relocation'];
116                 }
117         }
118
119         /**
120          * Wizard prev button callback actions.
121          *
122          * @param TWizard $sender sender object
123          * @param TWizardNavigationEventParameter $param sender parameters
124          * @return none
125          */
126         public function wizardPrev($sender, $param) {
127                 if ($param->CurrentStepIndex === 2) {
128                         $this->restore_single_jobid = $_SESSION['restore_single_jobid'];
129                         $this->loadBackupsForClient();
130                 } elseif ($param->CurrentStepIndex === 3) {
131                         $this->setFileVersions();
132                         $this->loadSelectedFiles();
133                         $this->loadFileVersions();
134                         $this->goToPath();
135                 } elseif ($param->CurrentStepIndex === 5) {
136                         $this->file_relocation_opt = $_SESSION['file_relocation'];
137                 }
138         }
139
140         /**
141          * Cancel wizard.
142          *
143          * @return none
144          */
145         public function wizardStop($sender, $param) {
146                 $this->resetWizard();
147                 $this->goToDefaultPage();
148         }
149
150         /**
151          * Load backup clients list (step 1).
152          *
153          * @param TActiveDropDownList $sender sender object
154          * @param TCommandParameter $param parameters object
155          * @return none
156          */
157         public function loadBackupClients() {
158                 $client_list = array();
159                 $clients = $this->getModule('api')->get(array('clients'))->output;
160                 for ($i = 0; $i < count($clients); $i++) {
161                         $client_list[$clients[$i]->name] = $clients[$i]->name;
162                 }
163                 asort($client_list);
164                 $this->BackupClientName->dataSource = $client_list;
165                 $this->BackupClientName->dataBind();
166         }
167
168         /**
169          * Load restore client list.
170          *
171          * @return none
172          */
173         public function loadRestoreClients() {
174                 $client_list = array();
175                 $clients = $this->getModule('api')->get(array('clients'))->output;
176                 for ($i = 0; $i < count($clients); $i++) {
177                         $client_list[$clients[$i]->name] = $clients[$i]->name;
178                 }
179                 $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue;
180                 $this->RestoreClient->dataSource = $client_list;
181                 $this->RestoreClient->dataBind();
182         }
183
184         /**
185          * Load backups for selected client (Step 2).
186          *
187          * @return none
188          */
189         public function loadBackupsForClient() {
190                 $clientid = $this->getBackupClientId();
191                 $jobs_for_client = $this->getModule('api')->get(array('clients', 'jobs', $clientid))->output;
192                 $jobs = $this->getModule('misc')->objectToArray($jobs_for_client);
193                 $this->BackupsToRestore->DataSource = array_filter($jobs, array($this, 'isBackupJobToRestore'));
194                 $this->BackupsToRestore->dataBind();
195         }
196
197         /**
198          * Check if job can be used in restore.
199          *
200          * @param array $job job properties
201          * @return true if job should be listed to restore, otherwise false
202          */
203         private function isBackupJobToRestore($job) {
204                 return ($job['type'] === 'B' && in_array($job['level'], $this->joblevel) && in_array($job['jobstatus'], $this->jobstatus));
205         }
206
207         public function loadBackupSelection($sender, $param) {
208                 $this->GroupBackupToRestoreField->Display = ($sender->ID == $this->GroupBackupSelection->ID) ? 'Dynamic' : 'None';
209                 $this->BackupToRestoreField->Display = ($sender->ID == $this->OnlySelectedBackupSelection->ID) ? 'Dynamic' : 'None';
210                 $this->setBrowserFiles();
211                 $this->setFileVersions();
212                 $this->setFilesToRestore();
213                 $this->markFileToRestore(null, null);
214                 $_SESSION['restore_path'] = array();
215         }
216
217
218         /**
219          * Get selected backup client identifier.
220          *
221          * @return mixed client identifier or null if no clientid found
222          */
223         public function getBackupClientId() {
224                 $clientid = null;
225                 $clients = $this->getModule('api')->get(array('clients'))->output;
226                 for ($i = 0; $i < count($clients); $i++) {
227                         if ($clients[$i]->name === $this->BackupClientName->SelectedValue) {
228                                 $clientid = $clients[$i]->clientid;
229                                 break;
230                         }
231                 }
232                 return $clientid;
233         }
234
235         /**
236          * Load backup jobs to restore for group most recent backups feature.
237          *
238          * @return none
239          */
240         public function loadGroupBackupToRestore() {
241                 $jobs = $this->getModule('api')->get(array('jobs'))->output;
242                 $jobs = $this->getModule('misc')->objectToArray($jobs);
243                 $clientid = $this->getBackupClientId();
244                 $job_group_list = array();
245                 for ($i = 0; $i < count($jobs); $i++) {
246                         $job = $this->getModule('misc')->objectToArray($jobs[$i]);
247                         if ($this->isBackupJobToRestore($jobs[$i]) && $jobs[$i]['clientid'] === $clientid) {
248                                 $job_group_list[$jobs[$i]['name']] = $jobs[$i]['name'];
249                         }
250                 }
251
252                 $this->GroupBackupToRestore->dataSource = $job_group_list;
253                 $this->GroupBackupToRestore->dataBind();
254         }
255
256         /**
257          * Load filesets to restore for group most recent backups feature.
258          *
259          * @return none
260          */
261         public function loadGroupFileSetToRestore() {
262                 $filesets = $this->getModule('api')->get(array('filesets', 'info'))->output;
263                 $fileset_list = array();
264                 for ($i = 0; $i < count($filesets); $i++) {
265                         $fileset_list[$filesets[$i]->filesetid] = $filesets[$i]->fileset . ' (' . $filesets[$i]->createtime . ')';
266                 }
267                 asort($fileset_list);
268
269                 $this->GroupBackupFileSet->dataSource = $fileset_list;
270                 $this->GroupBackupFileSet->dataBind();
271         }
272
273         /**
274          * Prepare left file browser content.
275          *
276          * @return none
277          */
278         private function prepareBrowserContent() {
279                 $jobids = $this->getElementaryBackup();
280                 $elements = array();
281                 if (!empty($jobids)) {
282                         // generating Bvfs may take a moment
283                         $this->generateBvfsCache($jobids);
284
285                         // get directories list
286                         $bvfs_dirs = $this->getModule('api')->set(
287                                 array('bvfs', 'lsdirs'),
288                                 array('jobids' => $jobids, 'path' => implode($_SESSION['restore_path']))
289                         );
290                         $dirs = $this->getModule('misc')->parseBvfsList($bvfs_dirs->output);
291
292                         // get files list
293                         $bvfs_files = $this->getModule('api')->set(
294                                 array('bvfs', 'lsfiles'),
295                                 array('jobids' => $jobids, 'path' =>  implode($_SESSION['restore_path']))
296                         );
297                         $files = $this->getModule('misc')->parseBvfsList($bvfs_files->output);
298
299                         $elements = array_merge($dirs, $files);
300                         if(count($_SESSION['restore_path']) > 0) {
301                                 array_unshift($elements, $this->browser_root_dir);
302                         }
303                 }
304                 $this->loadBrowserFiles($elements);
305         }
306
307         /*
308          * Get single elementary backup job identifiers.
309          *
310          * @return string comma separated job identifiers
311          */
312         private function getElementaryBackup() {
313                 $jobids = '';
314                 if($this->OnlySelectedBackupSelection->Checked && isset($_SESSION['restore_single_jobid'])) {
315                         $jobs = $this->getModule('api')->get(
316                                 array('bvfs', 'getjobids', $_SESSION['restore_single_jobid'])
317                         );
318                         $ids = is_object($jobs) ? $jobs->output : array();
319                         foreach ($ids as $jobid) {
320                                 if(preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) {
321                                         $jobids = $match[1];
322                                         break;
323                                 }
324                         }
325                 } else {
326                         $params = array(
327                                 'jobs',
328                                 'recent',
329                                 $this->GroupBackupToRestore->SelectedValue,
330                                 'client',
331                                 $this->BackupClientName->SelectedValue,
332                                 'filesetid',
333                                 $this->GroupBackupFileSet->SelectedValue
334                         );
335                         $jobs_recent = $this->getModule('api')->get($params);
336                         if (count($jobs_recent->output) > 0) {
337                                 $ids = $jobs_recent->output;
338                                 $jobids = implode(',', $ids);
339                         }
340                 }
341                 return $jobids;
342         }
343
344         /**
345          * Load path callback method.
346          * Used for manually typed paths in path field.
347          *
348          * @param TActiveLinkButton $sender sender object
349          * @param TEventParameter $param events parameter
350          * @return none
351          */
352         public function loadPath($sender, $param) {
353                 $path = explode('/', $this->PathField->Text);
354                 $path_len = count($path);
355                 for ($i = 0; $i < count($path); $i++) {
356                         if ($i == ($path_len - 1) && empty($path[$i])) {
357                                 // last path dir is slash so not add slash to last element
358                                 break;
359                         }
360                         $path[$i] .= '/';
361                 }
362                 $this->goToPath($path, true);
363         }
364
365         /**
366          * Go to specific path in the file browser.
367          * There is possible to pass both single directory 'somedir'
368          * or whole path '/etc/somedir'.
369          *
370          * @param string $path path to go
371          * @param bool $full_path determines if $path param is full path or relative path (singel directory)
372          * @return none
373          */
374         private function goToPath($path = '', $full_path = false) {
375                 if(!empty($path) && !$full_path) {
376                         if($path == $this->browser_up_dir['name']) {
377                                 array_pop($_SESSION['restore_path']);
378                         } elseif($path == $this->browser_root_dir['name']) {
379                                 $_SESSION['restore_path'] = array();
380                         } else {
381                                 array_push($_SESSION['restore_path'], $path);
382                         }
383                 }
384                 if ($full_path && is_array($path)) {
385                         $_SESSION['restore_path'] = $path;
386                 }
387                 $this->setBrowserPath();
388                 $this->prepareBrowserContent();
389         }
390
391         /**
392          * Add/mark file to restore.
393          * Used as callback to drag&drop browser elements.
394          *
395          * @param object $sender sender object
396          * @param object $param param object
397          * @return none
398          */
399         public function addFileToRestore($sender, $param) {
400                 $fileid = null;
401                 $source_element_id = null;
402                 $file_prop = array();
403                 if (isset($param->CallbackParameter)) {
404                         $id_parts = explode('_', $sender->ClientID, 6);
405                         $source_element_id = $id_parts[3];
406                         $fileid = $param->CallbackParameter;
407                 } else {
408                         $control = $param->getDroppedControl();
409                         $item = $control->getNamingContainer();
410                         $id_parts = explode('_', $param->getDragElementID(), 6);
411                         $source_element_id = $id_parts[3];
412                 }
413                 if($source_element_id == $this->VersionsDataGrid->ID) {
414                         if (is_null($fileid)) {
415                                 $fileid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex());
416                         }
417                         $file_prop = $this->getFileVersions($fileid);
418                 } else {
419                         if (is_null($fileid)) {
420                                 $fileid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex());
421                         }
422                         $file_prop = $this->getBrowserFile($fileid);
423                 }
424                 if($file_prop['name'] != $this->browser_root_dir['name'] && $file_prop['name'] != $this->browser_up_dir['name']) {
425                         $this->markFileToRestore($fileid, $file_prop);
426                         $this->loadSelectedFiles();
427                 }
428         }
429
430         /**
431          * Remove file from files marked to restre.
432          *
433          * @param TActiveImageButton $sender remove button object
434          * @param TEventParameter $param param object
435          * @return none
436          */
437         public function removeSelectedFile($sender, $param) {
438                 $fileid = $param->CallbackParameter;
439                 $this->unmarkFileToRestore($fileid);
440                 $this->loadSelectedFiles();
441         }
442
443         /**
444          * Get file backed up versions.
445          * Called as callback on file element click.
446          *
447          * @param TCallback $sender sender object
448          * @param object $param param object
449          * @return none
450          */
451         public function getVersions($sender, $param) {
452                 list($filename, $pathid, $filenameid, $jobid) = explode('|', $param->CallbackParameter, 4);
453                 if($filenameid == 0) {
454                         $this->goToPath($filename);
455                         return;
456                 }
457                 $clientname = $this->BackupClientName->SelectedValue;
458                 $versions = $this->getModule('api')->get(array('bvfs', 'versions', $clientname, $jobid, $pathid, $filenameid))->output;
459                 $file_versions = $this->getModule('misc')->parseFileVersions($filename, $versions);
460                 $this->setFileVersions($file_versions);
461                 $this->VersionsDataGrid->dataSource = $file_versions;
462                 $this->VersionsDataGrid->dataBind();
463                 $this->loadSelectedFiles();
464         }
465
466         /**
467          * Refresh/re-render selected files list.
468          *
469          * @param TDropContainer $sender sender object
470          * @param TEventParameter $param param object
471          * @return none
472          */
473         public function refreshSelectedFiles($sender, $param) {
474                 $this->loadSelectedFiles();
475                 $this->SelectedVersionsDropper->render($param->NewWriter);
476         }
477
478         /*
479          * Load file browser files to list.
480          *
481          * @param array $files files to list.
482          * @return none
483          */
484         private function loadBrowserFiles($files) {
485                 $this->setBrowserFiles($files);
486                 $this->DataGridFiles->dataSource = $files;
487                 $this->DataGridFiles->dataBind();
488         }
489
490         /**
491          * Load file versions area.
492          *
493          * @return none;
494          */
495         private function loadFileVersions() {
496                 $this->VersionsDataGrid->dataSource = $_SESSION['files_versions'];
497                 $this->VersionsDataGrid->dataBind();
498         }
499
500         /**
501          * Load selected files in drop area.
502          *
503          * @return none
504          */
505         private function loadSelectedFiles() {
506                 $this->SelectedVersionsDataGrid->dataSource = $_SESSION['restore'];
507                 $this->SelectedVersionsDataGrid->dataBind();
508         }
509
510         /**
511          * Set file browser path field.
512          *
513          * @return none
514          */
515         private function setBrowserPath() {
516                 $this->PathField->Text = implode($_SESSION['restore_path']);
517         }
518
519         /**
520          * Generate Bvfs cache by job identifiers.
521          *
522          * @param string $jobids comma separated job identifiers
523          * @return none
524          */
525         private function generateBvfsCache($jobids) {
526                 $this->getModule('api')->set(
527                         array('bvfs', 'update'),
528                         array('jobids' => $jobids)
529                 );
530         }
531
532         /**
533          * Set versions for selected file.
534          *
535          * @param array $versions file versions data
536          * @return none
537          */
538         private function setFileVersions($versions = array()) {
539                 $_SESSION['files_versions'] = $versions;
540         }
541
542         /**
543          * Get file versions for specified fileid.
544          *
545          * @param integer $fileid file identifier
546          * @return none
547          */
548         private function getFileVersions($fileid) {
549                 $versions = array();
550                 foreach($_SESSION['files_versions'] as $file) {
551                         if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
552                                 $versions = $file;
553                                 break;
554                         }
555                 }
556                 return $versions;
557         }
558
559         /**
560          * Set browser files.
561          *
562          * @param array $files file list
563          * @return none
564          */
565         private function setBrowserFiles($files = array()) {
566                 $_SESSION['files_browser'] = $files;
567         }
568
569         /**
570          * Get browser file by fileid.
571          *
572          * @param integer $fileid file identifier
573          * @return none
574          */
575         private function getBrowserFile($fileid) {
576                 $element = array();
577                 foreach($_SESSION['files_browser'] as $file) {
578                         if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
579                                 $element = $file;
580                                 break;
581                         }
582                 }
583                 return $element;
584         }
585
586         /**
587          * Mark file to restore.
588          *
589          * @param integer $fileid file identifier
590          * @param array $file file properties to mark
591          * @return none
592          */
593         private function markFileToRestore($fileid, $file) {
594                 if($fileid === null) {
595                         $_SESSION['restore'] = array();
596                 } elseif($file['name'] != $this->browser_root_dir['name'] && $file['name'] != $this->browser_up_dir['name']) {
597                         $_SESSION['restore'][$fileid] = $file;
598                 }
599         }
600
601         /**
602          * Unmark file to restore.
603          *
604          * @param integer $fileid file identifier
605          * @return none
606          */
607         private function unmarkFileToRestore($fileid) {
608                 if(array_key_exists($fileid, $_SESSION['restore'])) {
609                         unset($_SESSION['restore'][$fileid]);
610                 }
611         }
612
613         /**
614          * Get files to restore.
615          *
616          * @return array list with files to restore
617          */
618         public function getFilesToRestore() {
619                 return $_SESSION['restore'];
620         }
621
622         /**
623          * Set files to restore
624          *
625          * @param array $files files to restore
626          * @return none
627          */
628         public function setFilesToRestore($files = array()) {
629                 $_SESSION['restore'] = $files;
630         }
631
632         /**
633          * Get all restore elements (fileids and dirids).
634          *
635          * @param bool $as_object return result as object
636          * @return array list fileids and dirids
637          */
638         public function getRestoreElements($as_object = false) {
639                 $fileids = array();
640                 $dirids = array();
641                 $findexes = array();
642                 foreach ($this->getFilesToRestore() as $fileid => $properties) {
643                         if ($properties['type'] == 'dir') {
644                                 $dirids[] = $properties['pathid'];
645                         } elseif ($properties['type'] == 'file') {
646                                 $fileids[] = $fileid;
647                                 if ($properties['lstat']['linkfi'] !== 0) {
648                                         $findexes[] = $properties['jobid'] . ',' . $properties['lstat']['linkfi'];
649                                 }
650                         }
651                 }
652                 $ret = array('fileid' => $fileids, 'dirid' => $dirids, 'findex' => $findexes);
653                 if($as_object === true) {
654                         $ret = (object)$ret;
655                 }
656                 return $ret;
657         }
658
659         /**
660          * Wizard finish method.
661          *
662          * @return none
663          */
664         public function wizardCompleted() {
665                 $jobids = $this->getElementaryBackup();
666                 $path = self::BVFS_PATH_PREFIX . getmypid();
667                 $restore_elements = $this->getRestoreElements();
668                 $cmd_props = array('jobids' => $jobids, 'path' => $path);
669                 $is_element = false;
670                 if(count($restore_elements['fileid']) > 0) {
671                         $cmd_props['fileid'] = implode(',', $restore_elements['fileid']);
672                         $is_element = true;
673                 }
674                 if(count($restore_elements['dirid']) > 0) {
675                         $cmd_props['dirid'] = implode(',', $restore_elements['dirid']);
676                         $is_element = true;
677                 }
678                 if (count($restore_elements['findex']) > 0) {
679                         $cmd_props['findex'] = implode(',', $restore_elements['findex']);
680                         $is_element = true;
681                 }
682
683                 $jobid = null;
684                 if ($is_element) {
685                         $this->getModule('api')->create(array('bvfs', 'restore'), $cmd_props);
686                         $restore_props = array();
687                         $restore_props['rpath'] = $path;
688                         $restore_props['client'] = $this->RestoreClient->SelectedValue;
689                         $restore_props['priority'] = intval($this->RestoreJobPriority->Text);
690                         if ($_SESSION['file_relocation'] == 2) {
691                                 if (!empty($this->RestoreStripPrefix->Text)) {
692                                         $restore_props['strip_prefix'] = $this->RestoreStripPrefix->Text;
693                                 }
694                                 if (!empty($this->RestoreAddPrefix->Text)) {
695                                         $restore_props['add_prefix'] = $this->RestoreAddPrefix->Text;
696                                 }
697                                 if (!empty($this->RestoreAddSuffix->Text)) {
698                                         $restore_props['add_suffix'] = $this->RestoreAddSuffix->Text;
699                                 }
700                         } elseif ($_SESSION['file_relocation'] == 3) {
701                                 if (!empty($this->RestoreRegexWhere->Text)) {
702                                         $restore_props['regex_where'] = $this->RestoreRegexWhere->Text;
703                                 }
704                         }
705                         if (!array_key_exists('add_prefix', $restore_props)) {
706                                 $restore_props['where'] =  $this->RestorePath->Text;
707                         }
708                         $restore_props['replace'] = $this->ReplaceFiles->SelectedValue;
709                         $restore_props['restorejob'] = $this->RestoreJob->SelectedValue;
710
711                         $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restore_props);
712                         $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output);
713                 }
714                 $url_params = array('open' => 'Job');
715                 if (is_numeric($jobid)) {
716                         $url_params['id'] = $jobid;
717                 }
718                 $this->goToDefaultPage($url_params);
719         }
720
721         /**
722          * Load restore jobs on the list.
723          *
724          * @return none
725          */
726         private function loadRestoreJobs() {
727                 $restore_job_tasks = $this->getModule('api')->get(array('jobs', 'tasks', 'type', 'R'))->output;
728                 $jobs = array();
729                 foreach ($restore_job_tasks as $director => $restore_jobs) {
730                         $jobs = array_merge($jobs, $restore_jobs);
731                 }
732                 $this->RestoreJob->DataSource = array_combine($jobs, $jobs);
733                 $this->RestoreJob->dataBind();
734         }
735
736         private function loadRequiredVolumes() {
737                 $volumes = array();
738                 foreach ($this->getFilesToRestore() as $fileid => $props) {
739                         // it can be expensive for many restore paths
740                         $result = $this->getModule('api')->get(array('volumes', 'required', $props['jobid'], $fileid));
741                         if ($result->error === 0) {
742                                 for ($i = 0; $i < count($result->output); $i++) {
743                                         $volumes[$result->output[$i]->volume] = array(
744                                                 'volume' => $result->output[$i]->volume,
745                                                 'inchanger' => $result->output[$i]->inchanger
746                                         );
747                                 }
748                         }
749                 }
750                 $this->RestoreVolumes->DataSource = array_values($volumes);
751                 $this->RestoreVolumes->dataBind();
752         }
753
754         /**
755          * Reset wizard.
756          * All fields are back to initial form.
757          *
758          * @return none
759          */
760         private function resetWizard() {
761                 $this->setBrowserFiles();
762                 $this->setFileVersions();
763                 $this->setFilesToRestore();
764                 $this->markFileToRestore(null, null);
765                 $this->loadRestoreJobs();
766                 $_SESSION['restore_path'] = array();
767                 $_SESSION['restore_single_jobid'] = null;
768                 unset($_SESSION['file_relocation']);
769         }
770 }
771 ?>