'config_list.yaml', 'manage' => 'config_manage_list.yaml']; /** * @var boolean If set to true, core updates will not be downloaded or extracted. */ protected $disableCoreUpdates = false; public function __construct() { parent::__construct(); $this->addCss('/modules/system/assets/css/updates.css', 'core'); BackendMenu::setContext('October.System', 'system', 'updates'); SettingsManager::setContext('October.System', 'updates'); $this->disableCoreUpdates = Config::get('cms.disableCoreUpdates', false); } /** * Index controller */ public function index() { $this->vars['core_build'] = Parameters::get('system::core.build', '???'); $this->vars['project_id'] = Parameters::get('system::project.id'); $this->vars['project_name'] = Parameters::get('system::project.name'); $this->vars['project_owner'] = Parameters::get('system::project.owner'); return $this->asExtension('ListController')->index(); } /** * Plugin manage controller */ public function manage() { $this->pageTitle = 'system::lang.plugins.manage'; PluginManager::instance()->clearDisabledCache(); return $this->asExtension('ListController')->index(); } /** * {@inheritDoc} */ public function listInjectRowClass($record, $definition = null) { if ($record->disabledByConfig) { return 'hidden'; } if ($record->orphaned || $record->is_disabled) { return 'safe disabled'; } if ($definition != 'manage') { return; } if ($record->disabledBySystem) { return 'negative'; } return 'positive'; } /** * Runs a specific update step. */ public function onExecuteStep() { /* * Address timeout limits */ if (!ini_get('safe_mode')) { set_time_limit(3600); } $manager = UpdateManager::instance(); $stepCode = post('code'); switch ($stepCode) { case 'downloadCore': if ($this->disableCoreUpdates) { return; } $manager->downloadCore(post('hash')); break; case 'extractCore': if ($this->disableCoreUpdates) { return; } $manager->extractCore(post('hash'), post('build')); break; case 'downloadPlugin': $manager->downloadPlugin(post('name'), post('hash')); break; case 'downloadTheme': $manager->downloadTheme(post('name'), post('hash')); break; case 'extractPlugin': $manager->extractPlugin(post('name'), post('hash')); break; case 'extractTheme': $manager->extractTheme(post('name'), post('hash')); break; case 'completeUpdate': $manager->update(); Flash::success(Lang::get('system::lang.updates.update_success')); return Redirect::to(Backend::url('system/updates')); case 'completeInstall': $manager->update(); Flash::success(Lang::get('system::lang.install.install_success')); return Redirect::to(Backend::url('system/updates')); } } // // Updates // /** * Spawns the update checker popup. */ public function onLoadUpdates() { return $this->makePartial('update_form'); } /** * Contacts the update server for a list of necessary updates. */ public function onCheckForUpdates() { try { $manager = UpdateManager::instance(); $result = $manager->requestUpdateList(); $this->vars['core'] = array_get($result, 'core', false); $this->vars['hasUpdates'] = array_get($result, 'update', false); $this->vars['pluginList'] = array_get($result, 'plugins', []); $this->vars['themeList'] = array_get($result, 'themes', []); } catch (Exception $ex) { $this->handleError($ex); } return ['#updateContainer' => $this->makePartial('update_list')]; } /** * Contacts the update server for a list of necessary updates. */ public function onForceUpdate() { try { $manager = UpdateManager::instance(); $result = $manager->requestUpdateList(true); $coreHash = array_get($result, 'core.hash', false); $coreBuild = array_get($result, 'core.build', false); $core = [$coreHash, $coreBuild]; $plugins = []; $pluginList = array_get($result, 'plugins', []); foreach ($pluginList as $code => $plugin) { $plugins[$code] = array_get($plugin, 'hash', null); } $themes = []; $themeList = array_get($result, 'themes', []); foreach ($themeList as $code => $theme) { $themes[$code] = array_get($theme, 'hash', null); } /* * Update steps */ $updateSteps = $this->buildUpdateSteps($core, $plugins, $themes); /* * Finish up */ $updateSteps[] = [ 'code' => 'completeUpdate', 'label' => Lang::get('system::lang.updates.update_completing'), ]; $this->vars['updateSteps'] = $updateSteps; } catch (Exception $ex) { $this->handleError($ex); } return $this->makePartial('execute'); } /** * Converts the update data to an actionable array of steps. */ public function onApplyUpdates() { try { $coreHash = post('hash'); $coreBuild = post('build'); $core = [$coreHash, $coreBuild]; $plugins = post('plugins', []); if (!is_array($plugins)) { $plugins = []; } $themes = post('themes', []); if (!is_array($themes)) { $themes = []; } /* * Update steps */ $updateSteps = $this->buildUpdateSteps($core, $plugins, $themes); /* * Finish up */ $updateSteps[] = [ 'code' => 'completeUpdate', 'label' => Lang::get('system::lang.updates.update_completing'), ]; $this->vars['updateSteps'] = $updateSteps; } catch (Exception $ex) { $this->handleError($ex); } return $this->makePartial('execute'); } protected function buildUpdateSteps($core, $plugins, $themes) { if (!is_array($core)) { $core = [null, null]; } if (!is_array($plugins)) { $plugins = []; } if (!is_array($themes)) { $themes = []; } $updateSteps = []; list($coreHash, $coreBuild) = $core; /* * Download */ if ($coreHash) { $updateSteps[] = [ 'code' => 'downloadCore', 'label' => Lang::get('system::lang.updates.core_downloading'), 'hash' => $coreHash ]; } foreach ($plugins as $name => $hash) { $updateSteps[] = [ 'code' => 'downloadPlugin', 'label' => Lang::get('system::lang.updates.plugin_downloading', compact('name')), 'name' => $name, 'hash' => $hash ]; } foreach ($themes as $name => $hash) { $updateSteps[] = [ 'code' => 'downloadTheme', 'label' => Lang::get('system::lang.updates.theme_downloading', compact('name')), 'name' => $name, 'hash' => $hash ]; } /* * Extract */ if ($coreHash) { $updateSteps[] = [ 'code' => 'extractCore', 'label' => Lang::get('system::lang.updates.core_extracting'), 'hash' => $coreHash, 'build' => $coreBuild ]; } foreach ($plugins as $name => $hash) { $updateSteps[] = [ 'code' => 'extractPlugin', 'label' => Lang::get('system::lang.updates.plugin_extracting', compact('name')), 'name' => $name, 'hash' => $hash ]; } foreach ($themes as $name => $hash) { $updateSteps[] = [ 'code' => 'extractTheme', 'label' => Lang::get('system::lang.updates.theme_extracting', compact('name')), 'name' => $name, 'hash' => $hash ]; } return $updateSteps; } // // Bind to Project // /** * Displays the form for entering a Project ID */ public function onLoadProjectForm() { return $this->makePartial('project_form'); } /** * Validate the project ID and execute the project installation */ public function onAttachProject() { try { if (!$projectId = post('project_id')) { throw new ApplicationException(Lang::get('system::lang.project.id.missing')); } $manager = UpdateManager::instance(); $result = $manager->requestProjectDetails($projectId); Parameters::set([ 'system::project.id' => $projectId, 'system::project.name' => $result['name'], 'system::project.owner' => $result['owner'], ]); return $this->onForceUpdate(); } catch (Exception $ex) { $this->handleError($ex); return $this->makePartial('project_form'); } } public function onDetachProject() { Parameters::set([ 'system::project.id' => null, 'system::project.name' => null, 'system::project.owner' => null, ]); Flash::success(Lang::get('system::lang.project.unbind_success')); return Redirect::to(Backend::url('system/updates')); } // // Plugin management // /** * Validate the plugin code and execute the plugin installation */ public function onInstallPlugin() { try { if (!$code = post('code')) { throw new ApplicationException(Lang::get('system::lang.install.missing_plugin_name')); } $manager = UpdateManager::instance(); $result = $manager->requestPluginDetails($code); if (!isset($result['code']) || !isset($result['hash'])) { throw new ApplicationException(Lang::get('system::lang.server.response_invalid')); } $name = $result['code']; $hash = $result['hash']; $plugins = [$name => $hash]; /* * Update steps */ $updateSteps = $this->buildUpdateSteps(null, $plugins, []); /* * Finish up */ $updateSteps[] = [ 'code' => 'completeInstall', 'label' => Lang::get('system::lang.install.install_completing'), ]; $this->vars['updateSteps'] = $updateSteps; return $this->makePartial('execute'); } catch (Exception $ex) { $this->handleError($ex); return $this->makePartial('plugin_form'); } } /** * Removes or purges plugins from the system. * @return void */ public function onRemovePlugins() { if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) { foreach ($checkedIds as $objectId) { if (!$object = PluginVersion::find($objectId)) { continue; } /* * Rollback plugin */ $pluginCode = $object->code; UpdateManager::instance()->rollbackPlugin($pluginCode); /* * Delete from file system */ if ($pluginPath = PluginManager::instance()->getPluginPath($pluginCode)) { File::deleteDirectory($pluginPath); } } Flash::success(Lang::get('system::lang.plugins.remove_success')); } return $this->listRefresh('manage'); } /** * Rebuilds plugin database migrations. * @return void */ public function onRefreshPlugins() { if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) { $manager = UpdateManager::instance(); foreach ($checkedIds as $objectId) { if (!$object = PluginVersion::find($objectId)) { continue; } /* * Refresh plugin */ $pluginCode = $object->code; $manager->rollbackPlugin($pluginCode); $manager->updatePlugin($pluginCode); } Flash::success(Lang::get('system::lang.plugins.refresh_success')); } return $this->listRefresh('manage'); } public function onLoadDisableForm() { try { $this->vars['checked'] = post('checked'); } catch (Exception $ex) { $this->handleError($ex); } return $this->makePartial('disable_form'); } public function onDisablePlugins() { $disable = post('disable', false); if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) { $manager = PluginManager::instance(); foreach ($checkedIds as $objectId) { if (!$object = PluginVersion::find($objectId)) { continue; } if ($disable) { $manager->disablePlugin($object->code, true); } else { $manager->enablePlugin($object->code, true); } $object->is_disabled = $disable; $object->save(); } } if ($disable) { Flash::success(Lang::get('system::lang.plugins.disable_success')); } else { Flash::success(Lang::get('system::lang.plugins.enable_success')); } return Redirect::to(Backend::url('system/updates/manage')); } }