]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/protected/Web/Pages/RestoreWizard.php
baculum: Add fileset info endpoint and use it in 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.ActiveControls.TActiveDropDownList');
27 Prado::using('System.Web.UI.ActiveControls.TActivePanel');
28 Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
29 Prado::using('System.Web.UI.ActiveControls.TActiveImageButton');
30 Prado::using('System.Web.UI.ActiveControls.TDropContainer');
31 Prado::using('System.Web.UI.ActiveControls.TDraggable');
32 Prado::using('System.Web.UI.ActiveControls.TActiveRadioButton');
33 Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid');
34 Prado::using('System.Web.UI.ActiveControls.TCallback');
35
36 class RestoreWizard extends BaculumWebPage
37 {
38         private $job_levels_to_restore = array('F' => 'Full', 'I' => 'Incremental', 'D'=> 'Differential');
39         private $jobs = null;
40         private $filesets = null;
41         private $storages = null;
42         private $clients = null;
43         private $browser_root_dir = array('name' => '.', 'type' => 'dir');
44         private $browser_up_dir = array('name' => '..', 'type' => 'dir');
45
46         public $excluded_elements_from_add = array('.', '..');
47
48         const BVFS_PATH_PREFIX = 'b2';
49
50         public function onPreInit($param) {
51                 parent::onPreInit($param);
52                 $this->Application->getModule('web_users')->loginUser();
53         }
54
55         public function onInit($param) {
56                 parent::onInit($param);
57                 if(!$this->IsPostBack && !$this->IsCallBack) {
58                         $this->setBrowserFiles(array());
59                         $this->setFileVersions(array());
60                         $this->setFilesToRestore(array());
61                         $this->markFileToRestore(null, null);
62                         $this->setRestoreJobs();
63                         $_SESSION['restore_path'] = array();
64                 }
65         }
66
67         public function onLoad($param) {
68                 parent::onLoad($param);
69                         if($this->RestoreWizard->ActiveStepIndex == 0) {
70                                 $this->jobs = $this->getModule('api')->get(array('jobs'))->output;
71                                 $this->filesets = $this->getModule('api')->get(array('filesets', 'info'))->output;
72                         }
73                         $this->clients = $this->getModule('api')->get(array('clients'))->output;
74
75                         if(!$this->IsCallBack && (($this->RestoreWizard->ActiveStepIndex == 1 && $this->getPage()->BackupToRestore->ItemCount > 0) || $this->RestoreWizard->ActiveStepIndex == 3)) {
76                                 $this->setFileVersions(array());
77                                 $this->setBrowserPath('');
78                                 $this->prepareFilesToRestore();
79                                 $this->prepareVersionsToRestore();
80                         }
81         }
82
83         public function addFileToRestore($sender, $param) {
84                 $fileid = null;
85                 if (isset($param->callbackParameter)) {
86                         list(, , , $sourceElementID, , ) = explode('_', $sender->ClientID, 6);
87                         $fileid = $param->callbackParameter;
88                 } else {
89                         $control = $param->getDroppedControl();
90                         $item = $control->getNamingContainer();
91                         list(, , , $sourceElementID, , ) = explode('_', $param->getDragElementID(), 6); // I know that it is ugly.
92                 }
93                 if($sourceElementID == $this->VersionsDataGrid->ID) {
94                         if (is_null($fileid)) {
95                                 $fileid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex());
96                         }
97                         $fileProperties = $this->getFileVersions($fileid);
98                 } else {
99                         if (is_null($fileid)) {
100                                 $fileid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex());
101                         }
102                         $fileProperties = $this->getBrowserFile($fileid);
103                 }
104                 if($fileProperties['name'] != $this->browser_root_dir['name'] && $fileProperties['name'] != $this->browser_up_dir['name']) {
105                         $this->markFileToRestore($fileid, $fileProperties);
106                         $this->prepareFilesToRestore();
107                 }
108         }
109
110         public function removeSelectedFile($sender, $param) {
111                 $fileid = $param->CallbackParameter;
112                 $this->unmarkFileToRestore($fileid);
113                 $this->prepareFilesToRestore();
114         }
115
116         public function getVersions($sender, $param) {
117                 list($filename, $pathid, $filenameid, $jobid) = explode('|', $param->CallbackParameter, 4);
118                 if($filenameid == 0) {
119                         $this->setBrowserPath($filename);
120                         return;
121                 }
122                 $clientname = $this->BackupClientName->SelectedValue;
123                 $versions = $this->getModule('api')->get(array('bvfs', 'versions', $clientname, $jobid, $pathid, $filenameid))->output;
124                 $fileVersions = $this->getModule('misc')->parseFileVersions($filename, $versions);
125                 $this->setFileVersions($fileVersions);
126                 $this->VersionsDataGrid->dataSource = $fileVersions;
127                 $this->VersionsDataGrid->dataBind();
128                 $this->prepareFilesToRestore();
129         }
130
131         public function refreshSelectedFiles($sender, $param) {
132                 $this->prepareFilesToRestore();
133                 $this->SelectedVersionsDropper->render($param->NewWriter);
134         }
135
136         public function NextStep($sender, $param) {
137         }
138         
139         public function PreviousStep($sender, $param) {
140         }
141
142         public function wizardStop($sender, $param) {
143                 $this->goToDefaultPage();
144         }
145
146         public function setJobs($sender, $param) {
147                 $jobs_list = $jobs_group_list = array();
148                 $clientid = null;
149                 for ($i = 0; $i < count($this->clients); $i++) {
150                         if ($this->clients[$i]->name === $this->BackupClientName->SelectedValue) {
151                                 $clientid = $this->clients[$i]->clientid;
152                                 break;
153                         }
154                 }
155                 if(is_array($this->jobs)) {
156                         foreach($this->jobs as $job) {
157                                 if(array_key_exists($job->level, $this->job_levels_to_restore) && $job->type == 'B' && $job->jobstatus == 'T' && $job->clientid == $clientid) {
158                                         $jobs_list[$job->jobid] = sprintf('[%s] %s, %s, %s', $job->jobid, $job->name, $this->job_levels_to_restore[$job->level], $job->endtime);
159                                         $jobs_group_list[$job->name] = $job->name;
160                                 }
161                         }
162                 }
163
164                 $fileset_list = array();
165                 for ($i = 0; $i < count($this->filesets); $i++) {
166                         $fileset_list[$this->filesets[$i]->filesetid] = $this->filesets[$i]->fileset . ' (' . $this->filesets[$i]->createtime . ')';
167                 }
168                 asort($fileset_list);
169
170                 $this->BackupToRestore->dataSource = $jobs_list;
171                 $this->BackupToRestore->dataBind();
172                 $this->GroupBackupToRestore->dataSource = $jobs_group_list;
173                 $this->GroupBackupToRestore->dataBind();
174                 $this->GroupBackupFileSet->dataSource = $fileset_list;
175                 $this->GroupBackupFileSet->dataBind();
176                 $this->setRestoreClients($sender, $param);
177         }
178
179         public function setBackupClients($sender, $param) {
180                 if(!$this->IsPostBack) {
181                         $client_list = array();
182                         foreach($this->clients as $client) {
183                                 $client_list[$client->name] = $client->name;
184                         }
185                         $this->BackupClientName->dataSource = $client_list;
186                         $this->BackupClientName->dataBind();
187                 }
188         }
189
190         public function setRestoreClients($sender, $param) {
191                 if(!$this->IsPostBack || $sender->ID == $this->BackupClientName->ID) {
192                         $client_list = array();
193                         foreach($this->clients as $client) {
194                                 $client_list[$client->name] = $client->name;
195                         }
196                         $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue;
197                         $this->RestoreClient->dataSource = $client_list;
198                         $this->RestoreClient->dataBind();
199                 }
200         }
201
202         public function setBackupClient($sender, $param) {
203                 $this->ClientToRestore->SelectedValue = $param->SelectedValue;
204         } 
205
206         public function setBackupSelection($sender, $param) {
207                 $this->GroupBackupToRestoreField->Display = ($sender->ID == $this->GroupBackupSelection->ID) ? 'Dynamic' : 'None';
208                 $this->BackupToRestoreField->Display = ($sender->ID == $this->OnlySelectedBackupSelection->ID) ? 'Dynamic' : 'None';
209                 $this->setBrowserFiles(array());
210                 $this->setFileVersions(array());
211                 $this->setFilesToRestore(array());
212                 $this->markFileToRestore(null, null);
213                 $_SESSION['restore_path'] = array();
214         }
215
216         public function resetFileBrowser($sender, $param) {
217                 $this->markFileToRestore(null, null);
218                 $this->setBrowserPath($this->browser_root_dir['name']);
219         }
220
221         private function prepareBrowserFiles($files) {
222                 $this->setBrowserFiles($files);
223                 $this->DataGridFiles->dataSource = $files;
224                 @$this->DataGridFiles->dataBind();
225         }
226
227         private function prepareVersionsToRestore() {
228                 $this->VersionsDataGrid->dataSource = $_SESSION['files_versions'];
229                 $this->VersionsDataGrid->dataBind();
230         }
231
232         private function prepareFilesToRestore() {
233                 $this->SelectedVersionsDataGrid->dataSource = $_SESSION['restore'];
234                 $this->SelectedVersionsDataGrid->dataBind();
235         }
236
237         private function setBrowserPath($path) {
238                 if(!empty($path)) {
239                         if($path == $this->browser_up_dir['name']) {
240                                 array_pop($_SESSION['restore_path']);
241                         } elseif($path == $this->browser_root_dir['name']) {
242                                 $_SESSION['restore_path'] = array();
243                         } else {
244                                 array_push($_SESSION['restore_path'], $path);
245                         }
246                 }
247                 $this->setBrowserLocalizator();
248                 $this->prepareBrowserContent();
249         }
250
251         private function getBrowserPath($stringFormat = false) {
252                 return ($stringFormat === true) ? implode($_SESSION['restore_path']) : $_SESSION['restore_path'];
253         }
254
255         private function setBrowserLocalizator() {
256                 $localization = $this->getBrowserPath(true);
257                 $this->PathField->HeaderText = mb_strlen($localization) > 56 ? '...' . mb_substr($localization, -56) : $localization;
258         }
259
260         private function prepareBrowserContent() {
261                 $jobids = $this->getElementaryBackup();
262                 $elements = array();
263                 if (!is_null($jobids)) {
264                         // generating Bvfs may takes a moment
265                         $this->generateBvfsCacheByJobids($jobids);
266                         $bvfs_dirs_list = $this->getModule('api')->set(array('bvfs', 'lsdirs'), array('jobids' => $jobids, 'path' => $this->getBrowserPath(true)));
267                         $bvfs_dirs = is_object($bvfs_dirs_list) ? $bvfs_dirs_list->output : array();
268                         $dirs = $this->getModule('misc')->parseBvfsList($bvfs_dirs);
269                         $bvfs_files_list = $this->getModule('api')->set(array('bvfs', 'lsfiles'), array('jobids' => $jobids, 'path' => $this->getBrowserPath(true)));
270                         $bvfs_files = is_object($bvfs_files_list) ? $bvfs_files_list->output : array();
271                         $files = $this->getModule('misc')->parseBvfsList($bvfs_files);
272                         $elements = array_merge($dirs, $files);
273                         if(count($this->getBrowserPath()) > 0) {
274                                 array_unshift($elements, $this->browser_root_dir);
275                         }
276                 }
277                 $this->prepareBrowserFiles($elements);
278         }
279
280         private function getElementaryBackup() {
281                 $jobids = null;
282                 if($this->OnlySelectedBackupSelection->Checked === true) {
283                         $jobs = $this->getModule('api')->get(array('bvfs', 'getjobids', $this->BackupToRestore->SelectedValue));
284                         $ids = is_object($jobs) ? $jobs->output : array();
285                         foreach($ids as $jobid) {
286                                 if(preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) {
287                                         $jobids = $match[1];
288                                         break;
289                                 }
290                         }
291                 } else {
292                         $params = array(
293                                 'jobs',
294                                 'recent',
295                                 $this->GroupBackupToRestore->SelectedValue,
296                                 'client',
297                                 $this->BackupClientName->SelectedValue,
298                                 'filesetid',
299                                 $this->GroupBackupFileSet->SelectedValue
300                         );
301                         $jobs_recent = $this->getModule('api')->get($params);
302                         if(count($jobs_recent->output) > 0) {
303                                 $ids = $jobs_recent->output;
304                                 $jobids = implode(',', $ids);
305                         }
306                 }
307                 return $jobids;
308         }
309
310         private function generateBvfsCacheByJobids($jobids) {
311                 $this->getModule('api')->set(array('bvfs', 'update'), array('jobids' => $jobids));
312         }
313
314         private function setFileVersions($versions) {
315                 $_SESSION['files_versions'] = $versions;
316         }
317
318         private function getFileVersions($fileid) {
319                 $versions = array();
320                 foreach($_SESSION['files_versions'] as $file) {
321                         if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
322                                 $versions = $file;
323                                 break;
324                         }
325                 }
326                 return $versions;
327         }
328
329         private function setBrowserFiles($files) {
330                 $_SESSION['files_browser'] = $files;
331         }
332
333         private function getBrowserFile($fileid) {
334                 $element = array();
335                 foreach($_SESSION['files_browser'] as $file) {
336                         if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
337                                 $element = $file;
338                                 break;
339                         }
340                 }
341                 return $element;
342         }
343
344         private function markFileToRestore($fileid, $file) {
345                 if($fileid === null) {
346                         $_SESSION['restore'] = array();
347                 } elseif($file['name'] != $this->browser_root_dir['name'] && $file['name'] != $this->browser_up_dir['name']) {
348                         $_SESSION['restore'][$fileid] = $file;
349                 }
350         }
351
352         private function unmarkFileToRestore($fileid) {
353                 if(array_key_exists($fileid, $_SESSION['restore'])) {
354                         unset($_SESSION['restore'][$fileid]);
355                 }
356         }
357
358         public function getFilesToRestore() {
359                 return $_SESSION['restore'];
360         }
361
362         public function setFilesToRestore($files) {
363                 $_SESSION['restore'] = $files;
364         }
365
366         public function getRestoreElements($asObject = false) {
367                 $fileids = array();
368                 $dirids = array();
369                 foreach($this->getFilesToRestore() as $fileid => $properties) {
370                         if($properties['type'] == 'dir') {
371                                 $dirids[] = $properties['pathid'];
372                         } elseif($properties['type'] == 'file') {
373                                 $fileids[] = $fileid;
374                         }
375                 }
376                 $ret = array('fileid' => $fileids, 'dirid' => $dirids);
377                 if($asObject === true) {
378                         $ret = (object)$ret;
379                 }
380                 return $ret;
381         }
382
383         public function wizardCompleted() {
384                 $jobids = $this->getElementaryBackup();
385                 $path = self::BVFS_PATH_PREFIX . getmypid();
386                 $restore_elements = $this->getRestoreElements();
387                 $cmd_props = array('jobids' => $jobids, 'path' => $path);
388                 if(count($restore_elements['fileid']) > 0) {
389                         $cmd_props['fileid'] = implode(',', $restore_elements['fileid']);
390                 }
391                 if(count($restore_elements['dirid']) > 0) {
392                         $cmd_props['dirid'] = implode(',', $restore_elements['dirid']);
393                 }
394
395                 $this->getModule('api')->create(array('bvfs', 'restore'), $cmd_props);
396                 $restore_props = array();
397                 $restore_props['rpath'] = $path;
398                 $restore_props['client'] = $this->RestoreClient->SelectedValue;
399                 $restore_props['priority'] = intval($this->RestoreJobPriority->Text);
400                 $restore_props['where'] =  $this->RestorePath->Text;
401                 $restore_props['replace'] = $this->ReplaceFiles->SelectedValue;
402                 $restore_props['restorejob'] = $this->RestoreJob->SelectedValue;
403                 
404                 $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restore_props);
405                 $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output);
406                 $url_params = array('open' => 'Job');
407                 if (is_numeric($jobid)) {
408                         $url_params['id'] = $jobid;
409                 }
410                 $this->goToDefaultPage($url_params);
411         }
412
413         private function setRestoreJobs() {
414                 $restore_job_tasks = $this->Application->getModule('api')->get(array('jobs', 'tasks', 'type', 'R'))->output;
415                 $jobs = array();
416                 foreach ($restore_job_tasks as $director => $restore_jobs) {
417                         $jobs = array_merge($jobs, $restore_jobs);
418                 }
419                 $this->RestoreJob->DataSource = array_combine($jobs, $jobs);
420                 $this->RestoreJob->dataBind();
421         }
422 }
423 ?>