3 * Bacula® - The Network Backup Solution
4 * Baculum - Bacula web interface
6 * Copyright (C) 2013-2015 Marcin Haba
8 * The main author of Baculum is Marcin Haba.
9 * The main author of Bacula is Kern Sibbald, with contributions from many
10 * others, a complete list can be found in the file AUTHORS.
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.
17 * Bacula® is a registered trademark of Kern Sibbald.
20 Prado::using('System.Exceptions.TException');
21 Prado::using('System.Web.UI.ActiveControls.TActiveDropDownList');
22 Prado::using('System.Web.UI.ActiveControls.TActivePanel');
23 Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
24 Prado::using('System.Web.UI.ActiveControls.TActiveImageButton');
25 Prado::using('System.Web.UI.ActiveControls.TDropContainer');
26 Prado::using('System.Web.UI.ActiveControls.TDraggable');
27 Prado::using('System.Web.UI.ActiveControls.TActiveRadioButton');
28 Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid');
29 Prado::using('System.Web.UI.ActiveControls.TCallback');
31 class RestoreWizard extends BaculumPage
33 private $jobLevelsToRestore = array('F' => 'Full', 'I' => 'Incremental', 'D'=> 'Differential');
35 private $filesets = null;
36 private $storages = null;
37 private $clients = null;
38 private $browserRootDir = array('name' => '.', 'type' => 'dir');
39 private $browserUpDir = array('name' => '..', 'type' => 'dir');
41 public $excludedElementsFromAdd = array('.', '..');
43 const BVFS_PATH_PREFIX = 'b2';
45 public function onInit($param) {
46 parent::onInit($param);
47 if(!$this->IsPostBack && !$this->IsCallBack) {
48 $this->setBrowserFiles(array());
49 $this->setFileVersions(array());
50 $this->setFilesToRestore(array());
51 $this->markFileToRestore(null, null);
52 $_SESSION['restore_path'] = array();
56 public function onLoad($param) {
57 parent::onLoad($param);
58 if($this->RestoreWizard->ActiveStepIndex == 0) {
59 $this->jobs = $this->getModule('api')->get(array('jobs'))->output;
60 $this->filesets = $this->getModule('api')->get(array('filesets'))->output;
62 $this->clients = $this->getModule('api')->get(array('clients'))->output;
64 if(!$this->IsCallBack && (($this->RestoreWizard->ActiveStepIndex == 1 && $this->getPage()->BackupToRestore->ItemCount > 0) || $this->RestoreWizard->ActiveStepIndex == 3)) {
65 $this->setFileVersions(array());
66 $this->setBrowserPath('');
67 $this->prepareFilesToRestore();
68 $this->prepareVersionsToRestore();
72 public function addFileToRestore($sender, $param) {
74 if (isset($param->callbackParameter)) {
75 list(, , , $sourceElementID, , ) = explode('_', $sender->ClientID, 6);
76 $fileid = $param->callbackParameter;
78 $control = $param->getDroppedControl();
79 $item = $control->getNamingContainer();
80 list(, , , $sourceElementID, , ) = explode('_', $param->getDragElementID(), 6); // I know that it is ugly.
82 if($sourceElementID == $this->VersionsDataGrid->ID) {
83 if (is_null($fileid)) {
84 $fileid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex());
86 $fileProperties = $this->getFileVersions($fileid);
88 if (is_null($fileid)) {
89 $fileid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex());
91 $fileProperties = $this->getBrowserFile($fileid);
93 if($fileProperties['name'] != $this->browserRootDir['name'] && $fileProperties['name'] != $this->browserUpDir['name']) {
94 $this->markFileToRestore($fileid, $fileProperties);
95 $this->prepareFilesToRestore();
99 public function removeSelectedFile($sender, $param) {
100 $fileid = $param->CallbackParameter;
101 $this->unmarkFileToRestore($fileid);
102 $this->prepareFilesToRestore();
105 public function getVersions($sender, $param) {
106 list($filename, $pathid, $filenameid, $jobid) = explode('|', $param->CallbackParameter, 4);
107 if($filenameid == 0) {
108 $this->setBrowserPath($filename);
112 foreach($this->clients as $client) {
113 if($client->clientid == $this->BackupClientName->SelectedValue) {
114 $clientname = $client->name;
118 $versions = $this->getModule('api')->get(array('bvfs', 'versions', $clientname, $jobid, $pathid, $filenameid))->output;
119 $fileVersions = $this->getModule('misc')->parseFileVersions($filename, $versions);
120 $this->setFileVersions($fileVersions);
121 $this->VersionsDataGrid->dataSource = $fileVersions;
122 $this->VersionsDataGrid->dataBind();
123 $this->prepareFilesToRestore();
126 public function refreshSelectedFiles($sender, $param) {
127 $this->prepareFilesToRestore();
128 $this->SelectedVersionsDropper->render($param->NewWriter);
131 public function NextStep($sender, $param) {
134 public function PreviousStep($sender, $param) {
137 public function wizardStop($sender, $param) {
138 $this->goToDefaultPage();
141 public function setJobs($sender, $param) {
142 $jobsList = $jobsGroupList = $fileSetsList = array();
143 if(is_array($this->jobs)) {
144 foreach($this->jobs as $job) {
145 if(array_key_exists($job->level, $this->jobLevelsToRestore) && $job->type == 'B' && $job->jobstatus == 'T' && $job->clientid == $this->BackupClientName->SelectedValue) {
146 $jobsList[$job->jobid] = sprintf('[%s] %s, %s, %s', $job->jobid, $job->name, $this->jobLevelsToRestore[$job->level], $job->endtime);
147 $jobsGroupList[$job->name] = $job->name;
148 //$fileSetsList[$job->filesetid] = $this->getFileSet($job->filesetid)->fileset;
153 foreach($this->filesets as $director => $filesets) {
154 $fileSetsList = array_merge($filesets, $fileSetsList);
157 $this->BackupToRestore->dataSource = $jobsList;
158 $this->BackupToRestore->dataBind();
159 $this->GroupBackupToRestore->dataSource = $jobsGroupList;
160 $this->GroupBackupToRestore->dataBind();
161 $this->GroupBackupFileSet->dataSource = array_combine($fileSetsList, $fileSetsList);
162 $this->GroupBackupFileSet->dataBind();
163 $this->setRestoreClients($sender, $param);
166 public function setBackupClients($sender, $param) {
167 if(!$this->IsPostBack) {
168 $clientsList = array();
169 foreach($this->clients as $client) {
170 $clientsList[$client->clientid] = $client->name;
172 $this->BackupClientName->dataSource = $clientsList;
173 $this->BackupClientName->dataBind();
177 public function setRestoreClients($sender, $param) {
178 if(!$this->IsPostBack || $sender->ID == $this->BackupClientName->ID) {
179 $clientsList = array();
180 foreach($this->clients as $client) {
181 $clientsList[$client->clientid] = $client->name;
183 $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue;
184 $this->RestoreClient->dataSource = $clientsList;
185 $this->RestoreClient->dataBind();
189 public function getFileSet($filesetId) {
191 foreach($this->filesets as $fileset) {
192 if($fileset->filesetid == $filesetId) {
193 $filesetObj = $fileset;
200 public function setStorage($sender, $param) {
201 if(!$this->IsPostBack) {
202 $storagesList = array();
203 $storages = $this->getModule('api')->get(array('storages'))->output;
204 foreach($storages as $storage) {
205 $storagesList[$storage->storageid] = $storage->name;
207 $this->GroupBackupStorage->dataSource = $storagesList;
208 $this->GroupBackupStorage->dataBind();
212 public function setPool($sender, $param) {
213 if(!$this->IsPostBack) {
214 $poolsList = array();
215 $pools = $this->getModule('api')->get(array('pools'))->output;
216 foreach($pools as $pool) {
217 $poolsList[$pool->poolid] = $pool->name;
219 $this->GroupBackupPool->dataSource = $poolsList;
220 $this->GroupBackupPool->dataBind();
224 public function setBackupClient($sender, $param) {
225 $this->ClientToRestore->SelectedValue = $param->SelectedValue;
228 public function setBackupSelection($sender, $param) {
229 $this->GroupBackupToRestoreField->Display = ($sender->ID == $this->GroupBackupSelection->ID) ? 'Dynamic' : 'None';
230 $this->BackupToRestoreField->Display = ($sender->ID == $this->OnlySelectedBackupSelection->ID) ? 'Dynamic' : 'None';
231 $this->setBrowserFiles(array());
232 $this->setFileVersions(array());
233 $this->setFilesToRestore(array());
234 $this->markFileToRestore(null, null);
235 $_SESSION['restore_path'] = array();
238 /*public function setGroupBackup($sender, $param) {
239 foreach($this->jobs as $job) {
240 if($job->name == $sender->SelectedValue) {
241 $this->GroupBackupFileSet->SelectedValue = $job->filesetid;
246 public function resetFileBrowser($sender, $param) {
247 $this->markFileToRestore(null, null);
248 $this->setBrowserPath($this->browserRootDir['name']);
251 private function prepareBrowserFiles($files) {
252 $this->setBrowserFiles($files);
253 $this->DataGridFiles->dataSource = $files;
254 @$this->DataGridFiles->dataBind();
257 private function prepareVersionsToRestore() {
258 $this->VersionsDataGrid->dataSource = $_SESSION['files_versions'];
259 $this->VersionsDataGrid->dataBind();
262 private function prepareFilesToRestore() {
263 $this->SelectedVersionsDataGrid->dataSource = $_SESSION['restore'];
264 $this->SelectedVersionsDataGrid->dataBind();
267 private function setBrowserPath($path) {
269 if($path == $this->browserUpDir['name']) {
270 array_pop($_SESSION['restore_path']);
271 } elseif($path == $this->browserRootDir['name']) {
272 $_SESSION['restore_path'] = array();
274 array_push($_SESSION['restore_path'], $path);
277 $this->setBrowserLocalizator();
278 $this->prepareBrowserContent();
281 private function getBrowserPath($stringFormat = false) {
282 return ($stringFormat === true) ? implode($_SESSION['restore_path']) : $_SESSION['restore_path'];
285 private function setBrowserLocalizator() {
286 $localization = $this->getBrowserPath(true);
287 $this->PathField->HeaderText = mb_strlen($localization) > 56 ? '...' . mb_substr($localization, -56) : $localization;
290 private function prepareBrowserContent() {
291 $jobids = $this->getElementaryBackup();
293 // generating Bvfs may takes a moment
294 $this->generateBvfsCacheByJobids($jobids);
295 $bvfsDirsList = $this->getModule('api')->get(array('bvfs', 'lsdirs', $jobids, '?path=' . urlencode($this->getBrowserPath(true)) . ''));
296 $bvfsDirs = is_object($bvfsDirsList) ? $bvfsDirsList->output : array();
297 $dirs = $this->getModule('misc')->parseBvfsList($bvfsDirs);
298 $bvfsFilesList = $this->getModule('api')->get(array('bvfs', 'lsfiles', $jobids, '?path=' . urlencode($this->getBrowserPath(true)) . ''));
299 $bvfsFiles = is_object($bvfsFilesList) ? $bvfsFilesList->output : array();
300 $files = $this->getModule('misc')->parseBvfsList($bvfsFiles);
301 $elements = array_merge($dirs, $files);
302 if(count($this->getBrowserPath()) > 0) {
303 array_unshift($elements, $this->browserRootDir);
305 $this->prepareBrowserFiles($elements);
308 private function getElementaryBackup() {
310 if($this->OnlySelectedBackupSelection->Checked === true) {
311 $jobs = $this->getModule('api')->get(array('bvfs', 'getjobids', $this->BackupToRestore->SelectedValue));
312 $ids = is_object($jobs) ? $jobs->output : array();
313 foreach($ids as $jobid) {
314 if(preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) {
320 $jobsRecent = $this->getModule('api')->get(array('jobs', 'recent', urlencode($this->GroupBackupToRestore->SelectedValue), $this->BackupClientName->SelectedValue));
321 if(isset($jobsRecent->output) && count($jobsRecent->output) > 0) {
322 $ids = $jobsRecent->output;
323 $jobids = implode(',', $ids);
327 $completeJobids = (!is_null($jobids)) ? $jobids : $this->BackupToRestore->SelectedValue;
328 return $completeJobids;
331 private function generateBvfsCacheByJobids($jobids) {
332 $this->getModule('api')->set(array('bvfs', 'update', $jobids), array());
335 private function setFileVersions($versions) {
336 $_SESSION['files_versions'] = $versions;
339 private function getFileVersions($fileid) {
341 foreach($_SESSION['files_versions'] as $file) {
342 if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
350 private function setBrowserFiles($files) {
351 $_SESSION['files_browser'] = $files;
354 private function getBrowserFile($fileid) {
356 foreach($_SESSION['files_browser'] as $file) {
357 if(array_key_exists('fileid', $file) && $file['fileid'] == $fileid) {
365 private function markFileToRestore($fileid, $file) {
366 if($fileid === null) {
367 $_SESSION['restore'] = array();
368 } elseif($file['name'] != $this->browserRootDir['name'] && $file['name'] != $this->browserUpDir['name']) {
369 $_SESSION['restore'][$fileid] = $file;
373 private function unmarkFileToRestore($fileid) {
374 if(array_key_exists($fileid, $_SESSION['restore'])) {
375 unset($_SESSION['restore'][$fileid]);
379 public function getFilesToRestore() {
380 return $_SESSION['restore'];
383 public function setFilesToRestore($files) {
384 $_SESSION['restore'] = $files;
387 public function getRestoreElements($asObject = false) {
390 foreach($this->getFilesToRestore() as $fileid => $properties) {
391 if($properties['type'] == 'dir') {
392 $dirids[] = $properties['pathid'];
393 } elseif($properties['type'] == 'file') {
394 $fileids[] = $fileid;
397 $ret = array('fileid' => $fileids, 'dirid' => $dirids);
398 if($asObject === true) {
404 public function wizardCompleted() {
405 $jobids = $this->getElementaryBackup();
406 $path = self::BVFS_PATH_PREFIX . str_replace(',', '', $jobids);
407 $restoreElements = $this->getRestoreElements();
408 $cmdProps = array('jobids' => $jobids, 'path' => $path);
409 if(count($restoreElements['fileid']) > 0) {
410 $cmdProps['fileid'] = implode(',', $restoreElements['fileid']);
412 if(count($restoreElements['dirid']) > 0) {
413 $cmdProps['dirid'] = implode(',', $restoreElements['dirid']);
416 $this->getModule('api')->create(array('bvfs', 'restore'), $cmdProps);
417 $restoreProps = array();
418 $restoreProps['rpath'] = $path;
419 $restoreProps['clientid'] = intval($this->RestoreClient->SelectedValue);
420 $restoreProps['fileset'] = $this->GroupBackupFileSet->SelectedValue;
421 $restoreProps['priority'] = intval($this->RestoreJobPriority->Text);
422 $restoreProps['where'] = $this->RestorePath->Text;
423 $restoreProps['replace'] = $this->ReplaceFiles->SelectedValue;
425 $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restoreProps);
426 $this->goToDefaultPage(array('open' => 'Job'));