X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=gui%2Fbaculum%2Fprotected%2FWeb%2FPages%2FRestoreWizard.php;h=aeffaec46aa0daac8910bb3e94d6021320bc4b88;hb=6c59aff866ff412b46f1d171fc99f2e303a509f0;hp=4d88700e6356c908008f86a289ed53d52731246a;hpb=2f10e42cf4544d881e16b22051aca6d87331322a;p=bacula%2Fbacula diff --git a/gui/baculum/protected/Web/Pages/RestoreWizard.php b/gui/baculum/protected/Web/Pages/RestoreWizard.php index 4d88700e63..aeffaec46a 100644 --- a/gui/baculum/protected/Web/Pages/RestoreWizard.php +++ b/gui/baculum/protected/Web/Pages/RestoreWizard.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2016 Kern Sibbald + * Copyright (C) 2013-2017 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -23,329 +23,528 @@ Prado::using('Application.Web.Class.BaculumWebPage'); Prado::using('System.Exceptions.TException'); Prado::using('System.Web.UI.WebControls.TWizard'); -Prado::using('System.Web.UI.ActiveControls.TActiveDropDownList'); -Prado::using('System.Web.UI.ActiveControls.TActivePanel'); +Prado::using('System.Web.UI.WebControls.TDataGrid'); Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton'); Prado::using('System.Web.UI.ActiveControls.TActiveImageButton'); Prado::using('System.Web.UI.ActiveControls.TDropContainer'); Prado::using('System.Web.UI.ActiveControls.TDraggable'); -Prado::using('System.Web.UI.ActiveControls.TActiveRadioButton'); Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid'); Prado::using('System.Web.UI.ActiveControls.TCallback'); +Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); class RestoreWizard extends BaculumWebPage { - private $jobLevelsToRestore = array('F' => 'Full', 'I' => 'Incremental', 'D'=> 'Differential'); - private $jobs = null; - private $filesets = null; - private $storages = null; - private $clients = null; - private $browserRootDir = array('name' => '.', 'type' => 'dir'); - private $browserUpDir = array('name' => '..', 'type' => 'dir'); - - public $excludedElementsFromAdd = array('.', '..'); - + /** + * Job levels allowed to restore. + */ + + private $joblevel = array('F', 'I', 'D'); + /** + * Job statuses allowed to restore. + */ + private $jobstatus = array('T', 'W', 'A', 'E', 'e', 'f'); + + /** + * File browser special directories. + */ + private $browser_root_dir = array('name' => '.', 'type' => 'dir', 'fileid' => null); + private $browser_up_dir = array('name' => '..', 'type' => 'dir'); + + /** + * Used to provide in template selected by user single jobid to restore. + */ + public $restore_single_jobid; + + /** + * Stores file relocation option. Used in template. + */ + public $file_relocation_opt; + + /** + * FIle browser elements for which 'Add' button is unavailable. + */ + public $excluded_elements_from_add = array('.', '..'); + + /** + * Prefix for Bvfs path. + */ const BVFS_PATH_PREFIX = 'b2'; - public function onPreInit($param) { - parent::onPreInit($param); - $this->Application->getModule('web_users')->loginUser(); - } - public function onInit($param) { parent::onInit($param); if(!$this->IsPostBack && !$this->IsCallBack) { - $this->setBrowserFiles(array()); - $this->setFileVersions(array()); - $this->setFilesToRestore(array()); - $this->markFileToRestore(null, null); - $_SESSION['restore_path'] = array(); + $this->resetWizard(); + $this->loadBackupClients(); } } - public function onLoad($param) { - parent::onLoad($param); - if($this->RestoreWizard->ActiveStepIndex == 0) { - $this->jobs = $this->getModule('api')->get(array('jobs'))->output; - $this->filesets = $this->getModule('api')->get(array('filesets'))->output; + /** + * Wizard next button callback actions. + * + * @param TWizard $sender sender object + * @param TWizardNavigationEventParameter $param sender parameters + * @return none + */ + public function wizardNext($sender, $param) { + if ($param->CurrentStepIndex === 0) { + $this->loadBackupsForClient(); + $this->loadGroupBackupToRestore(); + $this->loadGroupFileSetToRestore(); + $this->loadRestoreClients(); + if (isset($_SESSION['restore_single_jobid'])) { + $this->restore_single_jobid = $_SESSION['restore_single_jobid']; } - $this->clients = $this->getModule('api')->get(array('clients'))->output; - - if(!$this->IsCallBack && (($this->RestoreWizard->ActiveStepIndex == 1 && $this->getPage()->BackupToRestore->ItemCount > 0) || $this->RestoreWizard->ActiveStepIndex == 3)) { - $this->setFileVersions(array()); - $this->setBrowserPath(''); - $this->prepareFilesToRestore(); - $this->prepareVersionsToRestore(); + } elseif ($param->CurrentStepIndex === 1) { + if ($this->Request->contains('backup_to_restore')) { + $_SESSION['restore_single_jobid'] = $this->Request['backup_to_restore']; } - } - - public function addFileToRestore($sender, $param) { - $fileid = null; - if (isset($param->callbackParameter)) { - list(, , , $sourceElementID, , ) = explode('_', $sender->ClientID, 6); - $fileid = $param->callbackParameter; - } else { - $control = $param->getDroppedControl(); - $item = $control->getNamingContainer(); - list(, , , $sourceElementID, , ) = explode('_', $param->getDragElementID(), 6); // I know that it is ugly. - } - if($sourceElementID == $this->VersionsDataGrid->ID) { - if (is_null($fileid)) { - $fileid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex()); + $this->setFileVersions(); + $this->loadSelectedFiles(); + $this->loadFileVersions(); + $this->goToPath(); + } elseif ($param->CurrentStepIndex === 2) { + $this->loadRequiredVolumes(); + } elseif ($param->CurrentStepIndex === 3) { + if (isset($_SESSION['file_relocation'])) { + $this->file_relocation_opt = $_SESSION['file_relocation']; } - $fileProperties = $this->getFileVersions($fileid); - } else { - if (is_null($fileid)) { - $fileid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex()); + } elseif ($param->CurrentStepIndex === 4) { + if ($this->Request->contains('file_relocation')) { + $_SESSION['file_relocation'] = $this->Request['file_relocation']; } - $fileProperties = $this->getBrowserFile($fileid); + $this->file_relocation_opt = $_SESSION['file_relocation']; } - if($fileProperties['name'] != $this->browserRootDir['name'] && $fileProperties['name'] != $this->browserUpDir['name']) { - $this->markFileToRestore($fileid, $fileProperties); - $this->prepareFilesToRestore(); - } - } - - public function removeSelectedFile($sender, $param) { - $fileid = $param->CallbackParameter; - $this->unmarkFileToRestore($fileid); - $this->prepareFilesToRestore(); } - public function getVersions($sender, $param) { - list($filename, $pathid, $filenameid, $jobid) = explode('|', $param->CallbackParameter, 4); - if($filenameid == 0) { - $this->setBrowserPath($filename); - return; - } - $clientname = null; - foreach($this->clients as $client) { - if($client->clientid == $this->BackupClientName->SelectedValue) { - $clientname = $client->name; - break; - } + /** + * Wizard prev button callback actions. + * + * @param TWizard $sender sender object + * @param TWizardNavigationEventParameter $param sender parameters + * @return none + */ + public function wizardPrev($sender, $param) { + if ($param->CurrentStepIndex === 2) { + $this->restore_single_jobid = $_SESSION['restore_single_jobid']; + $this->loadBackupsForClient(); + } elseif ($param->CurrentStepIndex === 3) { + $this->setFileVersions(); + $this->loadSelectedFiles(); + $this->loadFileVersions(); + $this->goToPath(); + } elseif ($param->CurrentStepIndex === 5) { + $this->file_relocation_opt = $_SESSION['file_relocation']; } - $versions = $this->getModule('api')->get(array('bvfs', 'versions', $clientname, $jobid, $pathid, $filenameid))->output; - $fileVersions = $this->getModule('misc')->parseFileVersions($filename, $versions); - $this->setFileVersions($fileVersions); - $this->VersionsDataGrid->dataSource = $fileVersions; - $this->VersionsDataGrid->dataBind(); - $this->prepareFilesToRestore(); } - public function refreshSelectedFiles($sender, $param) { - $this->prepareFilesToRestore(); - $this->SelectedVersionsDropper->render($param->NewWriter); + /** + * Cancel wizard. + * + * @return none + */ + public function wizardStop($sender, $param) { + $this->resetWizard(); + $this->goToDefaultPage(); } - public function NextStep($sender, $param) { - } - - public function PreviousStep($sender, $param) { + /** + * Load backup clients list (step 1). + * + * @param TActiveDropDownList $sender sender object + * @param TCommandParameter $param parameters object + * @return none + */ + public function loadBackupClients() { + $client_list = array(); + $clients = $this->getModule('api')->get(array('clients'))->output; + for ($i = 0; $i < count($clients); $i++) { + $client_list[$clients[$i]->name] = $clients[$i]->name; + } + asort($client_list); + $this->BackupClientName->dataSource = $client_list; + $this->BackupClientName->dataBind(); + } + + /** + * Load restore client list. + * + * @return none + */ + public function loadRestoreClients() { + $client_list = array(); + $clients = $this->getModule('api')->get(array('clients'))->output; + for ($i = 0; $i < count($clients); $i++) { + $client_list[$clients[$i]->name] = $clients[$i]->name; + } + $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue; + $this->RestoreClient->dataSource = $client_list; + $this->RestoreClient->dataBind(); + } + + /** + * Load backups for selected client (Step 2). + * + * @return none + */ + public function loadBackupsForClient() { + $clientid = $this->getBackupClientId(); + $jobs_for_client = $this->getModule('api')->get(array('clients', 'jobs', $clientid))->output; + $jobs = $this->getModule('misc')->objectToArray($jobs_for_client); + $this->BackupsToRestore->DataSource = array_filter($jobs, array($this, 'isBackupJobToRestore')); + $this->BackupsToRestore->dataBind(); + } + + /** + * Check if job can be used in restore. + * + * @param array $job job properties + * @return true if job should be listed to restore, otherwise false + */ + private function isBackupJobToRestore($job) { + return ($job['type'] === 'B' && in_array($job['level'], $this->joblevel) && in_array($job['jobstatus'], $this->jobstatus)); + } + + public function loadBackupSelection($sender, $param) { + $this->GroupBackupToRestoreField->Display = ($sender->ID == $this->GroupBackupSelection->ID) ? 'Dynamic' : 'None'; + $this->BackupToRestoreField->Display = ($sender->ID == $this->OnlySelectedBackupSelection->ID) ? 'Dynamic' : 'None'; + $this->setBrowserFiles(); + $this->setFileVersions(); + $this->setFilesToRestore(); + $this->markFileToRestore(null, null); + $_SESSION['restore_path'] = array(); } - public function wizardStop($sender, $param) { - $this->goToDefaultPage(); - } - public function setJobs($sender, $param) { - $jobsList = $jobsGroupList = $fileSetsList = array(); - if(is_array($this->jobs)) { - foreach($this->jobs as $job) { - if(array_key_exists($job->level, $this->jobLevelsToRestore) && $job->type == 'B' && $job->jobstatus == 'T' && $job->clientid == $this->BackupClientName->SelectedValue) { - $jobsList[$job->jobid] = sprintf('[%s] %s, %s, %s', $job->jobid, $job->name, $this->jobLevelsToRestore[$job->level], $job->endtime); - $jobsGroupList[$job->name] = $job->name; - //$fileSetsList[$job->filesetid] = $this->getFileSet($job->filesetid)->fileset; - } + /** + * Get selected backup client identifier. + * + * @return mixed client identifier or null if no clientid found + */ + public function getBackupClientId() { + $clientid = null; + $clients = $this->getModule('api')->get(array('clients'))->output; + for ($i = 0; $i < count($clients); $i++) { + if ($clients[$i]->name === $this->BackupClientName->SelectedValue) { + $clientid = $clients[$i]->clientid; + break; } } - - foreach($this->filesets as $director => $filesets) { - $fileSetsList = array_merge($filesets, $fileSetsList); + return $clientid; + } + + /** + * Load backup jobs to restore for group most recent backups feature. + * + * @return none + */ + public function loadGroupBackupToRestore() { + $jobs = $this->getModule('api')->get(array('jobs'))->output; + $jobs = $this->getModule('misc')->objectToArray($jobs); + $clientid = $this->getBackupClientId(); + $job_group_list = array(); + for ($i = 0; $i < count($jobs); $i++) { + $job = $this->getModule('misc')->objectToArray($jobs[$i]); + if ($this->isBackupJobToRestore($jobs[$i]) && $jobs[$i]['clientid'] === $clientid) { + $job_group_list[$jobs[$i]['name']] = $jobs[$i]['name']; + } } - $this->BackupToRestore->dataSource = $jobsList; - $this->BackupToRestore->dataBind(); - $this->GroupBackupToRestore->dataSource = $jobsGroupList; + $this->GroupBackupToRestore->dataSource = $job_group_list; $this->GroupBackupToRestore->dataBind(); - $this->GroupBackupFileSet->dataSource = array_combine($fileSetsList, $fileSetsList); - $this->GroupBackupFileSet->dataBind(); - $this->setRestoreClients($sender, $param); } - public function setBackupClients($sender, $param) { - if(!$this->IsPostBack) { - $clientsList = array(); - foreach($this->clients as $client) { - $clientsList[$client->clientid] = $client->name; - } - $this->BackupClientName->dataSource = $clientsList; - $this->BackupClientName->dataBind(); + /** + * Load filesets to restore for group most recent backups feature. + * + * @return none + */ + public function loadGroupFileSetToRestore() { + $filesets = $this->getModule('api')->get(array('filesets', 'info'))->output; + $fileset_list = array(); + for ($i = 0; $i < count($filesets); $i++) { + $fileset_list[$filesets[$i]->filesetid] = $filesets[$i]->fileset . ' (' . $filesets[$i]->createtime . ')'; } + asort($fileset_list); + + $this->GroupBackupFileSet->dataSource = $fileset_list; + $this->GroupBackupFileSet->dataBind(); } - public function setRestoreClients($sender, $param) { - if(!$this->IsPostBack || $sender->ID == $this->BackupClientName->ID) { - $clientsList = array(); - foreach($this->clients as $client) { - $clientsList[$client->clientid] = $client->name; + /** + * Prepare left file browser content. + * + * @return none + */ + private function prepareBrowserContent() { + $jobids = $this->getElementaryBackup(); + $elements = array(); + if (!empty($jobids)) { + // generating Bvfs may take a moment + $this->generateBvfsCache($jobids); + + // get directories list + $bvfs_dirs = $this->getModule('api')->set( + array('bvfs', 'lsdirs'), + array('jobids' => $jobids, 'path' => implode($_SESSION['restore_path'])) + ); + $dirs = $this->getModule('misc')->parseBvfsList($bvfs_dirs->output); + + // get files list + $bvfs_files = $this->getModule('api')->set( + array('bvfs', 'lsfiles'), + array('jobids' => $jobids, 'path' => implode($_SESSION['restore_path'])) + ); + $files = $this->getModule('misc')->parseBvfsList($bvfs_files->output); + + $elements = array_merge($dirs, $files); + if(count($_SESSION['restore_path']) > 0) { + array_unshift($elements, $this->browser_root_dir); } - $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue; - $this->RestoreClient->dataSource = $clientsList; - $this->RestoreClient->dataBind(); } + $this->loadBrowserFiles($elements); } - public function getFileSet($filesetId) { - $filesetObj = null; - foreach($this->filesets as $fileset) { - if($fileset->filesetid == $filesetId) { - $filesetObj = $fileset; + /* + * Get single elementary backup job identifiers. + * + * @return string comma separated job identifiers + */ + private function getElementaryBackup() { + $jobids = ''; + if($this->OnlySelectedBackupSelection->Checked && isset($_SESSION['restore_single_jobid'])) { + $jobs = $this->getModule('api')->get( + array('bvfs', 'getjobids', $_SESSION['restore_single_jobid']) + ); + $ids = is_object($jobs) ? $jobs->output : array(); + foreach ($ids as $jobid) { + if(preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) { + $jobids = $match[1]; + break; + } + } + } else { + $params = array( + 'jobs', + 'recent', + $this->GroupBackupToRestore->SelectedValue, + 'client', + $this->BackupClientName->SelectedValue, + 'filesetid', + $this->GroupBackupFileSet->SelectedValue + ); + $jobs_recent = $this->getModule('api')->get($params); + if (count($jobs_recent->output) > 0) { + $ids = $jobs_recent->output; + $jobids = implode(',', $ids); + } + } + return $jobids; + } + + /** + * Load path callback method. + * Used for manually typed paths in path field. + * + * @param TActiveLinkButton $sender sender object + * @param TEventParameter $param events parameter + * @return none + */ + public function loadPath($sender, $param) { + $path = explode('/', $this->PathField->Text); + $path_len = count($path); + for ($i = 0; $i < count($path); $i++) { + if ($i == ($path_len - 1) && empty($path[$i])) { + // last path dir is slash so not add slash to last element break; } + $path[$i] .= '/'; } - return $filesetObj; - } - - public function setStorage($sender, $param) { - if(!$this->IsPostBack) { - $storagesList = array(); - $storages = $this->getModule('api')->get(array('storages'))->output; - foreach($storages as $storage) { - $storagesList[$storage->storageid] = $storage->name; + $this->goToPath($path, true); + } + + /** + * Go to specific path in the file browser. + * There is possible to pass both single directory 'somedir' + * or whole path '/etc/somedir'. + * + * @param string $path path to go + * @param bool $full_path determines if $path param is full path or relative path (singel directory) + * @return none + */ + private function goToPath($path = '', $full_path = false) { + if(!empty($path) && !$full_path) { + if($path == $this->browser_up_dir['name']) { + array_pop($_SESSION['restore_path']); + } elseif($path == $this->browser_root_dir['name']) { + $_SESSION['restore_path'] = array(); + } else { + array_push($_SESSION['restore_path'], $path); } - $this->GroupBackupStorage->dataSource = $storagesList; - $this->GroupBackupStorage->dataBind(); } + if ($full_path && is_array($path)) { + $_SESSION['restore_path'] = $path; + } + $this->setBrowserPath(); + $this->prepareBrowserContent(); } - public function setPool($sender, $param) { - if(!$this->IsPostBack) { - $poolsList = array(); - $pools = $this->getModule('api')->get(array('pools'))->output; - foreach($pools as $pool) { - $poolsList[$pool->poolid] = $pool->name; + /** + * Add/mark file to restore. + * Used as callback to drag&drop browser elements. + * + * @param object $sender sender object + * @param object $param param object + * @return none + */ + public function addFileToRestore($sender, $param) { + $fileid = null; + $source_element_id = null; + $file_prop = array(); + if (isset($param->CallbackParameter)) { + $id_parts = explode('_', $sender->ClientID, 6); + $source_element_id = $id_parts[3]; + $fileid = $param->CallbackParameter; + } else { + $control = $param->getDroppedControl(); + $item = $control->getNamingContainer(); + $id_parts = explode('_', $param->getDragElementID(), 6); + $source_element_id = $id_parts[3]; + } + if($source_element_id == $this->VersionsDataGrid->ID) { + if (is_null($fileid)) { + $fileid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex()); + } + $file_prop = $this->getFileVersions($fileid); + } else { + if (is_null($fileid)) { + $fileid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex()); } - $this->GroupBackupPool->dataSource = $poolsList; - $this->GroupBackupPool->dataBind(); + $file_prop = $this->getBrowserFile($fileid); + } + if($file_prop['name'] != $this->browser_root_dir['name'] && $file_prop['name'] != $this->browser_up_dir['name']) { + $this->markFileToRestore($fileid, $file_prop); + $this->loadSelectedFiles(); } } - public function setBackupClient($sender, $param) { - $this->ClientToRestore->SelectedValue = $param->SelectedValue; - } - - public function setBackupSelection($sender, $param) { - $this->GroupBackupToRestoreField->Display = ($sender->ID == $this->GroupBackupSelection->ID) ? 'Dynamic' : 'None'; - $this->BackupToRestoreField->Display = ($sender->ID == $this->OnlySelectedBackupSelection->ID) ? 'Dynamic' : 'None'; - $this->setBrowserFiles(array()); - $this->setFileVersions(array()); - $this->setFilesToRestore(array()); - $this->markFileToRestore(null, null); - $_SESSION['restore_path'] = array(); + /** + * Remove file from files marked to restre. + * + * @param TActiveImageButton $sender remove button object + * @param TEventParameter $param param object + * @return none + */ + public function removeSelectedFile($sender, $param) { + $fileid = $param->CallbackParameter; + $this->unmarkFileToRestore($fileid); + $this->loadSelectedFiles(); } - /*public function setGroupBackup($sender, $param) { - foreach($this->jobs as $job) { - if($job->name == $sender->SelectedValue) { - $this->GroupBackupFileSet->SelectedValue = $job->filesetid; - } + /** + * Get file backed up versions. + * Called as callback on file element click. + * + * @param TCallback $sender sender object + * @param object $param param object + * @return none + */ + public function getVersions($sender, $param) { + list($filename, $pathid, $filenameid, $jobid) = explode('|', $param->CallbackParameter, 4); + if($filenameid == 0) { + $this->goToPath($filename); + return; } - }*/ + $clientname = $this->BackupClientName->SelectedValue; + $versions = $this->getModule('api')->get(array('bvfs', 'versions', $clientname, $jobid, $pathid, $filenameid))->output; + $file_versions = $this->getModule('misc')->parseFileVersions($filename, $versions); + $this->setFileVersions($file_versions); + $this->VersionsDataGrid->dataSource = $file_versions; + $this->VersionsDataGrid->dataBind(); + $this->loadSelectedFiles(); + } - public function resetFileBrowser($sender, $param) { - $this->markFileToRestore(null, null); - $this->setBrowserPath($this->browserRootDir['name']); + /** + * Refresh/re-render selected files list. + * + * @param TDropContainer $sender sender object + * @param TEventParameter $param param object + * @return none + */ + public function refreshSelectedFiles($sender, $param) { + $this->loadSelectedFiles(); + $this->SelectedVersionsDropper->render($param->NewWriter); } - private function prepareBrowserFiles($files) { + /* + * Load file browser files to list. + * + * @param array $files files to list. + * @return none + */ + private function loadBrowserFiles($files) { $this->setBrowserFiles($files); $this->DataGridFiles->dataSource = $files; - @$this->DataGridFiles->dataBind(); + $this->DataGridFiles->dataBind(); } - private function prepareVersionsToRestore() { + /** + * Load file versions area. + * + * @return none; + */ + private function loadFileVersions() { $this->VersionsDataGrid->dataSource = $_SESSION['files_versions']; $this->VersionsDataGrid->dataBind(); } - private function prepareFilesToRestore() { + /** + * Load selected files in drop area. + * + * @return none + */ + private function loadSelectedFiles() { $this->SelectedVersionsDataGrid->dataSource = $_SESSION['restore']; $this->SelectedVersionsDataGrid->dataBind(); } - private function setBrowserPath($path) { - if(!empty($path)) { - if($path == $this->browserUpDir['name']) { - array_pop($_SESSION['restore_path']); - } elseif($path == $this->browserRootDir['name']) { - $_SESSION['restore_path'] = array(); - } else { - array_push($_SESSION['restore_path'], $path); - } - } - $this->setBrowserLocalizator(); - $this->prepareBrowserContent(); - } - - private function getBrowserPath($stringFormat = false) { - return ($stringFormat === true) ? implode($_SESSION['restore_path']) : $_SESSION['restore_path']; - } - - private function setBrowserLocalizator() { - $localization = $this->getBrowserPath(true); - $this->PathField->HeaderText = mb_strlen($localization) > 56 ? '...' . mb_substr($localization, -56) : $localization; - } - - private function prepareBrowserContent() { - $jobids = $this->getElementaryBackup(); - - // generating Bvfs may takes a moment - $this->generateBvfsCacheByJobids($jobids); - $bvfsDirsList = $this->getModule('api')->set(array('bvfs', 'lsdirs'), array('jobids' => $jobids, 'path' => $this->getBrowserPath(true))); - $bvfsDirs = is_object($bvfsDirsList) ? $bvfsDirsList->output : array(); - $dirs = $this->getModule('misc')->parseBvfsList($bvfsDirs); - $bvfsFilesList = $this->getModule('api')->set(array('bvfs', 'lsfiles'), array('jobids' => $jobids, 'path' => $this->getBrowserPath(true))); - $bvfsFiles = is_object($bvfsFilesList) ? $bvfsFilesList->output : array(); - $files = $this->getModule('misc')->parseBvfsList($bvfsFiles); - $elements = array_merge($dirs, $files); - if(count($this->getBrowserPath()) > 0) { - array_unshift($elements, $this->browserRootDir); - } - $this->prepareBrowserFiles($elements); - } - - private function getElementaryBackup() { - $jobids = null; - if($this->OnlySelectedBackupSelection->Checked === true) { - $jobs = $this->getModule('api')->get(array('bvfs', 'getjobids', $this->BackupToRestore->SelectedValue)); - $ids = is_object($jobs) ? $jobs->output : array(); - foreach($ids as $jobid) { - if(preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) { - $jobids = $match[1]; - break; - } - } - } else { - $jobsRecent = $this->getModule('api')->get(array('jobs', 'recent', $this->GroupBackupToRestore->SelectedValue, $this->BackupClientName->SelectedValue)); - if(isset($jobsRecent->output) && count($jobsRecent->output) > 0) { - $ids = $jobsRecent->output; - $jobids = implode(',', $ids); - } - } - - $completeJobids = (!is_null($jobids)) ? $jobids : $this->BackupToRestore->SelectedValue; - return $completeJobids; - } - - private function generateBvfsCacheByJobids($jobids) { - $this->getModule('api')->set(array('bvfs', 'update'), array('jobids' => $jobids)); - } - - private function setFileVersions($versions) { + /** + * Set file browser path field. + * + * @return none + */ + private function setBrowserPath() { + $this->PathField->Text = implode($_SESSION['restore_path']); + } + + /** + * Generate Bvfs cache by job identifiers. + * + * @param string $jobids comma separated job identifiers + * @return none + */ + private function generateBvfsCache($jobids) { + $this->getModule('api')->set( + array('bvfs', 'update'), + array('jobids' => $jobids) + ); + } + + /** + * Set versions for selected file. + * + * @param array $versions file versions data + * @return none + */ + private function setFileVersions($versions = array()) { $_SESSION['files_versions'] = $versions; } + /** + * Get file versions for specified fileid. + * + * @param integer $fileid file identifier + * @return none + */ private function getFileVersions($fileid) { $versions = array(); foreach($_SESSION['files_versions'] as $file) { @@ -357,10 +556,22 @@ class RestoreWizard extends BaculumWebPage return $versions; } - private function setBrowserFiles($files) { + /** + * Set browser files. + * + * @param array $files file list + * @return none + */ + private function setBrowserFiles($files = array()) { $_SESSION['files_browser'] = $files; } + /** + * Get browser file by fileid. + * + * @param integer $fileid file identifier + * @return none + */ private function getBrowserFile($fileid) { $element = array(); foreach($_SESSION['files_browser'] as $file) { @@ -372,73 +583,189 @@ class RestoreWizard extends BaculumWebPage return $element; } + /** + * Mark file to restore. + * + * @param integer $fileid file identifier + * @param array $file file properties to mark + * @return none + */ private function markFileToRestore($fileid, $file) { if($fileid === null) { $_SESSION['restore'] = array(); - } elseif($file['name'] != $this->browserRootDir['name'] && $file['name'] != $this->browserUpDir['name']) { + } elseif($file['name'] != $this->browser_root_dir['name'] && $file['name'] != $this->browser_up_dir['name']) { $_SESSION['restore'][$fileid] = $file; } } + /** + * Unmark file to restore. + * + * @param integer $fileid file identifier + * @return none + */ private function unmarkFileToRestore($fileid) { if(array_key_exists($fileid, $_SESSION['restore'])) { unset($_SESSION['restore'][$fileid]); } } + /** + * Get files to restore. + * + * @return array list with files to restore + */ public function getFilesToRestore() { return $_SESSION['restore']; } - public function setFilesToRestore($files) { + /** + * Set files to restore + * + * @param array $files files to restore + * @return none + */ + public function setFilesToRestore($files = array()) { $_SESSION['restore'] = $files; } - public function getRestoreElements($asObject = false) { + /** + * Get all restore elements (fileids and dirids). + * + * @param bool $as_object return result as object + * @return array list fileids and dirids + */ + public function getRestoreElements($as_object = false) { $fileids = array(); $dirids = array(); - foreach($this->getFilesToRestore() as $fileid => $properties) { - if($properties['type'] == 'dir') { + $findexes = array(); + foreach ($this->getFilesToRestore() as $fileid => $properties) { + if ($properties['type'] == 'dir') { $dirids[] = $properties['pathid']; - } elseif($properties['type'] == 'file') { + } elseif ($properties['type'] == 'file') { $fileids[] = $fileid; + if ($properties['lstat']['linkfi'] !== 0) { + $findexes[] = $properties['jobid'] . ',' . $properties['lstat']['linkfi']; + } } } - $ret = array('fileid' => $fileids, 'dirid' => $dirids); - if($asObject === true) { + $ret = array('fileid' => $fileids, 'dirid' => $dirids, 'findex' => $findexes); + if($as_object === true) { $ret = (object)$ret; } return $ret; } + /** + * Wizard finish method. + * + * @return none + */ public function wizardCompleted() { $jobids = $this->getElementaryBackup(); - $path = self::BVFS_PATH_PREFIX . str_replace(',', '', $jobids); - $restoreElements = $this->getRestoreElements(); - $cmdProps = array('jobids' => $jobids, 'path' => $path); - if(count($restoreElements['fileid']) > 0) { - $cmdProps['fileid'] = implode(',', $restoreElements['fileid']); + $path = self::BVFS_PATH_PREFIX . getmypid(); + $restore_elements = $this->getRestoreElements(); + $cmd_props = array('jobids' => $jobids, 'path' => $path); + $is_element = false; + if(count($restore_elements['fileid']) > 0) { + $cmd_props['fileid'] = implode(',', $restore_elements['fileid']); + $is_element = true; + } + if(count($restore_elements['dirid']) > 0) { + $cmd_props['dirid'] = implode(',', $restore_elements['dirid']); + $is_element = true; } - if(count($restoreElements['dirid']) > 0) { - $cmdProps['dirid'] = implode(',', $restoreElements['dirid']); + if (count($restore_elements['findex']) > 0) { + $cmd_props['findex'] = implode(',', $restore_elements['findex']); + $is_element = true; } - $this->getModule('api')->create(array('bvfs', 'restore'), $cmdProps); - $restoreProps = array(); - $restoreProps['rpath'] = $path; - $restoreProps['clientid'] = intval($this->RestoreClient->SelectedValue); - $restoreProps['fileset'] = $this->GroupBackupFileSet->SelectedValue; - $restoreProps['priority'] = intval($this->RestoreJobPriority->Text); - $restoreProps['where'] = $this->RestorePath->Text; - $restoreProps['replace'] = $this->ReplaceFiles->SelectedValue; - - $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restoreProps); - $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output); - $urlParams = array('open' => 'Job'); + $jobid = null; + if ($is_element) { + $this->getModule('api')->create(array('bvfs', 'restore'), $cmd_props); + $restore_props = array(); + $restore_props['rpath'] = $path; + $restore_props['client'] = $this->RestoreClient->SelectedValue; + $restore_props['priority'] = intval($this->RestoreJobPriority->Text); + if ($_SESSION['file_relocation'] == 2) { + if (!empty($this->RestoreStripPrefix->Text)) { + $restore_props['strip_prefix'] = $this->RestoreStripPrefix->Text; + } + if (!empty($this->RestoreAddPrefix->Text)) { + $restore_props['add_prefix'] = $this->RestoreAddPrefix->Text; + } + if (!empty($this->RestoreAddSuffix->Text)) { + $restore_props['add_suffix'] = $this->RestoreAddSuffix->Text; + } + } elseif ($_SESSION['file_relocation'] == 3) { + if (!empty($this->RestoreRegexWhere->Text)) { + $restore_props['regex_where'] = $this->RestoreRegexWhere->Text; + } + } + if (!array_key_exists('add_prefix', $restore_props)) { + $restore_props['where'] = $this->RestorePath->Text; + } + $restore_props['replace'] = $this->ReplaceFiles->SelectedValue; + $restore_props['restorejob'] = $this->RestoreJob->SelectedValue; + + $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restore_props); + $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output); + } + $url_params = array('open' => 'Job'); if (is_numeric($jobid)) { - $urlParams['id'] = $jobid; + $url_params['id'] = $jobid; } - $this->goToDefaultPage($urlParams); + $this->goToDefaultPage($url_params); + } + + /** + * Load restore jobs on the list. + * + * @return none + */ + private function loadRestoreJobs() { + $restore_job_tasks = $this->getModule('api')->get(array('jobs', 'tasks', 'type', 'R'))->output; + $jobs = array(); + foreach ($restore_job_tasks as $director => $restore_jobs) { + $jobs = array_merge($jobs, $restore_jobs); + } + $this->RestoreJob->DataSource = array_combine($jobs, $jobs); + $this->RestoreJob->dataBind(); + } + + private function loadRequiredVolumes() { + $volumes = array(); + foreach ($this->getFilesToRestore() as $fileid => $props) { + // it can be expensive for many restore paths + $result = $this->getModule('api')->get(array('volumes', 'required', $props['jobid'], $fileid)); + if ($result->error === 0) { + for ($i = 0; $i < count($result->output); $i++) { + $volumes[$result->output[$i]->volume] = array( + 'volume' => $result->output[$i]->volume, + 'inchanger' => $result->output[$i]->inchanger + ); + } + } + } + $this->RestoreVolumes->DataSource = array_values($volumes); + $this->RestoreVolumes->dataBind(); + } + + /** + * Reset wizard. + * All fields are back to initial form. + * + * @return none + */ + private function resetWizard() { + $this->setBrowserFiles(); + $this->setFileVersions(); + $this->setFilesToRestore(); + $this->markFileToRestore(null, null); + $this->loadRestoreJobs(); + $_SESSION['restore_path'] = array(); + $_SESSION['restore_single_jobid'] = null; + unset($_SESSION['file_relocation']); } } ?>