From c7256134baf3f0526e0652684a8c5acc072ff50f Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 22 Feb 2017 21:34:21 +0100 Subject: [PATCH] [WORK IN PROGRESS] First draft of a Tools menu with direct install (#990) * First draft of a Tools menu with direct install * Basic styling * Translate GPM messages * Basic frontend validation * Fix form action path * Added lang strings for offical_gpm_only toggle --- admin.php | 12 ++++ classes/admin.php | 32 ++++++--- classes/admincontroller.php | 26 ++++++++ classes/gpm.php | 66 +++++++++---------- languages/en.yaml | 12 +++- pages/admin/tools.md | 7 ++ themes/grav/css-compiled/template.css | 2 +- themes/grav/scss/template/_admin.scss | 11 ++++ themes/grav/templates/partials/nav.html.twig | 27 +++++--- .../partials/tools-direct-install.html.twig | 30 +++++++++ themes/grav/templates/tools.html.twig | 28 ++++++++ 11 files changed, 199 insertions(+), 54 deletions(-) create mode 100644 pages/admin/tools.md create mode 100644 themes/grav/templates/partials/tools-direct-install.html.twig create mode 100644 themes/grav/templates/tools.html.twig diff --git a/admin.php b/admin.php index 8a9cd477..36d4ee2e 100644 --- a/admin.php +++ b/admin.php @@ -88,6 +88,7 @@ class AdminPlugin extends Plugin 'onShutdown' => ['onShutdown', 1000], 'onFormProcessed' => ['onFormProcessed', 0], 'onAdminDashboard' => ['onAdminDashboard', 0], + 'onAdminTools' => ['onAdminTools', 0], ]; } @@ -725,6 +726,17 @@ class AdminPlugin extends Plugin return false; } + /** + * Provide the tools for the Tools page, currently only direct install + * + * @return Event + */ + public function onAdminTools(Event $event) + { + $event['tools'] = array_merge($event['tools'], [$this->grav['language']->translate('PLUGIN_ADMIN.DIRECT_INSTALL')]); + return $event; + } + public function onAdminDashboard() { $this->grav['twig']->plugins_hooked_dashboard_widgets_top[] = ['template' => 'dashboard-maintenance']; diff --git a/classes/admin.php b/classes/admin.php index 3cc00917..12252a4f 100644 --- a/classes/admin.php +++ b/classes/admin.php @@ -184,6 +184,18 @@ class Admin return $configurations; } + /** + * Return the tools found + * + * @return array + */ + public static function tools() + { + $tools = []; + $event = Grav::instance()->fireEvent('onAdminTools', new Event(['tools' => &$tools])); + return $tools; + } + /** * Return the languages available in the site * @@ -365,8 +377,10 @@ class Admin * * @return string */ - public function translate($args, $languages = null) + public static function translate($args, $languages = null) { + $grav = Grav::instance(); + if (is_array($args)) { $lookup = array_shift($args); } else { @@ -375,7 +389,7 @@ class Admin } if (!$languages) { - $languages = [$this->grav['user']->authenticated ? $this->grav['user']->language : 'en']; + $languages = [$grav['user']->authenticated ? $grav['user']->language : 'en']; } else { $languages = (array)$languages; } @@ -383,25 +397,25 @@ class Admin if ($lookup) { if (empty($languages) || reset($languages) == null) { - if ($this->grav['config']->get('system.languages.translations_fallback', true)) { - $languages = $this->grav['language']->getFallbackLanguages(); + if ($grav['config']->get('system.languages.translations_fallback', true)) { + $languages = $grav['language']->getFallbackLanguages(); } else { - $languages = (array)$this->grav['language']->getDefault(); + $languages = (array)$grav['language']->getDefault(); } } } foreach ((array)$languages as $lang) { - $translation = $this->grav['language']->getTranslation($lang, $lookup); + $translation = $grav['language']->getTranslation($lang, $lookup); if (!$translation) { - $language = $this->grav['language']->getDefault() ?: 'en'; - $translation = $this->grav['language']->getTranslation($language, $lookup); + $language = $grav['language']->getDefault() ?: 'en'; + $translation = $grav['language']->getTranslation($language, $lookup); } if (!$translation) { $language = 'en'; - $translation = $this->grav['language']->getTranslation($language, $lookup); + $translation = $grav['language']->getTranslation($language, $lookup); } if ($translation) { diff --git a/classes/admincontroller.php b/classes/admincontroller.php index 2b48b6d0..8f76edfe 100644 --- a/classes/admincontroller.php +++ b/classes/admincontroller.php @@ -2090,4 +2090,30 @@ class AdminController extends AdminBaseController return $filename . '.md'; } + + /** + * Handle direct install. + * + */ + protected function taskDirectInstall() + { + $file_path = ''; + + if (isset($_FILES['uploaded_file'])) { + $file_path = $_FILES['uploaded_file']['tmp_name']; + } else { + $file_path = $this->data['file_path']; + } + + $result = Gpm::directInstall($file_path); + + if ($result === true) { + $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INSTALLATION_SUCCESSFUL'), 'info'); + } else { + $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INSTALLATION_FAILED') . ': ' . $result, 'error'); + } + + $this->setRedirect('/tools'); + } + } diff --git a/classes/gpm.php b/classes/gpm.php index 958ef0f4..4a3addab 100644 --- a/classes/gpm.php +++ b/classes/gpm.php @@ -56,15 +56,14 @@ class Gpm { $options = array_merge(self::$options, $options); - if ( - !Installer::isGravInstance($options['destination']) - || !Installer::isValidDestination($options['destination'], [Installer::EXISTS, Installer::IS_LINK]) + if (!Installer::isGravInstance($options['destination']) || !Installer::isValidDestination($options['destination'], + [Installer::EXISTS, Installer::IS_LINK]) ) { return false; } $packages = is_array($packages) ? $packages : [$packages]; - $count = count($packages); + $count = count($packages); $packages = array_filter(array_map(function ($p) { return !is_string($p) ? $p instanceof Package ? $p : false : self::GPM()->findPackage($p); @@ -97,7 +96,7 @@ class Gpm } $license = Licenses::get($package->slug); - $local = static::download($package, $license); + $local = static::download($package, $license); Installer::install($local, $options['destination'], ['install_path' => $package->install_path, 'theme' => $options['theme']]); @@ -146,14 +145,14 @@ class Gpm $options = array_merge(self::$options, $options); $packages = is_array($packages) ? $packages : [$packages]; - $count = count($packages); + $count = count($packages); $packages = array_filter(array_map(function ($p) { if (is_string($p)) { - $p = strtolower($p); + $p = strtolower($p); $plugin = static::GPM()->getInstalledPlugin($p); - $p = $plugin ?: static::GPM()->getInstalledTheme($p); + $p = $plugin ?: static::GPM()->getInstalledTheme($p); } return $p instanceof Package ? $p : false; @@ -198,10 +197,15 @@ class Gpm * Direct install a file * * @param $package_file + * * @return bool */ public static function directInstall($package_file) { + if (!$package_file) { + return Admin::translate('PLUGIN_ADMIN.NO_PACKAGE_NAME'); + } + $tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true); $tmp_zip = $tmp_dir . '/Grav-' . uniqid(); @@ -216,49 +220,50 @@ class Gpm $extracted = Installer::unZip($zip, $tmp_source); if (!$extracted) { - return "Package extraction failed."; + return Admin::translate('PLUGIN_ADMIN.PACKAGE_EXTRACTION_FAILED'); } $type = GravGPM::getPackageType($extracted); if (!$type) { - return "Not a valid Grav package"; + return Admin::translate('PLUGIN_ADMIN.NOT_VALID_GRAV_PACKAGE'); } if ($type == 'grav') { Installer::isValidDestination(GRAV_ROOT . '/system'); if (Installer::IS_LINK === Installer::lastErrorCode()) { - return "Cannot overwrite symlinks"; + return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS'); } - Installer::install($zip, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true], $extracted); + Installer::install($zip, GRAV_ROOT, + ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true], $extracted); } else { $name = GravGPM::getPackageName($extracted); if (!$name) { - return "Name could not be determined"; + return Admin::translate('PLUGIN_ADMIN.NAME_COULD_NOT_BE_DETERMINED'); } $install_path = GravGPM::getInstallPath($type, $name); $is_update = file_exists($install_path); - Installer::isValidDestination(GRAV_ROOT . DS . $install_path); if (Installer::lastErrorCode() == Installer::IS_LINK) { - return "Cannot overwrite symlinks"; + return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS'); } - Installer::install($zip, GRAV_ROOT, ['install_path' => $install_path, 'theme' => (($type == 'theme')), 'is_update' => $is_update], $extracted); + Installer::install($zip, GRAV_ROOT, + ['install_path' => $install_path, 'theme' => (($type == 'theme')), 'is_update' => $is_update], + $extracted); } Folder::delete($tmp_source); - - if(Installer::lastErrorCode()) { + if (Installer::lastErrorCode()) { return Installer::lastErrorMsg(); } } else { - return "ZIP package could not be found"; + return Admin::translate('PLUGIN_ADMIN.ZIP_PACKAGE_NOT_FOUND'); } Folder::delete($tmp_zip); @@ -276,14 +281,11 @@ class Gpm $query = ''; if ($package->premium) { - $query = \json_encode(array_merge( - $package->premium, - [ + $query = \json_encode(array_merge($package->premium, [ 'slug' => $package->slug, 'filename' => $package->premium['filename'], 'license_key' => $license - ] - )); + ])); $query = '?d=' . base64_encode($query); } @@ -297,9 +299,7 @@ class Gpm $tmp_dir = Admin::getTempDir() . '/Grav-' . uniqid(); Folder::mkdir($tmp_dir); - $bad_chars = array_merge( - array_map('chr', range(0, 31)), - array("<", ">", ":", '"', "/", "\\", "|", "?", "*")); + $bad_chars = array_merge(array_map('chr', range(0, 31)), ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]); $filename = $package->slug . str_replace($bad_chars, "", basename($package->zipball_url)); @@ -341,12 +341,11 @@ class Gpm } if (method_exists($upgrader, 'meetsRequirements') && !$upgrader->meetsRequirements()) { - $error = []; + $error = []; $error[] = '

Grav has increased the minimum PHP requirement.
'; $error[] = 'You are currently running PHP ' . PHP_VERSION . ''; $error[] = ', but PHP ' . GRAV_PHP_MIN . ' is required.

'; - $error[] = - '

Additional information

'; + $error[] = '

Additional information

'; Installer::setError(implode("\n", $error)); @@ -354,11 +353,10 @@ class Gpm } $update = $upgrader->getAssets()['grav-update']; - $tmp = Admin::getTempDir() . '/Grav-' . uniqid(); - $file = self::_downloadSelfupgrade($update, $tmp); + $tmp = Admin::getTempDir() . '/Grav-' . uniqid(); + $file = self::_downloadSelfupgrade($update, $tmp); - Installer::install($file, GRAV_ROOT, - ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true]); + Installer::install($file, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true]); $errorCode = Installer::lastErrorCode(); diff --git a/languages/en.yaml b/languages/en.yaml index 46916eb1..89328e17 100644 --- a/languages/en.yaml +++ b/languages/en.yaml @@ -644,4 +644,14 @@ PLUGIN_ADMIN: ERROR_REINSTALLING_THE: "Error reinstalling the %s" PACKAGE_X_REINSTALLED_SUCCESSFULLY: "Package %s reinstalled successfully" REINSTALLATION_FAILED: "Reinstallation failed" - WARNING_REINSTALL_NOT_LATEST_RELEASE: "The installed version is not the latest release. By clicking Continue, you'll remove the current version and install the latest available release" \ No newline at end of file + WARNING_REINSTALL_NOT_LATEST_RELEASE: "The installed version is not the latest release. By clicking Continue, you'll remove the current version and install the latest available release" + TOOLS: "Tools" + DIRECT_INSTALL: "Direct Install" + NO_PACKAGE_NAME: "Package name not specified" + PACKAGE_EXTRACTION_FAILED: "Package extraction failed" + NOT_VALID_GRAV_PACKAGE: "Not a valid Grav package" + NAME_COULD_NOT_BE_DETERMINED: "Name could not be determined" + CANNOT_OVERWRITE_SYMLINKS: "Cannot overwrite symlinks" + ZIP_PACKAGE_NOT_FOUND: "ZIP package could not be found" + GPM_OFFICIAL_ONLY: "Official GPM Only" + GPM_OFFICIAL_ONLY_HELP: "Only allow direct installs from the official GPM repository only." \ No newline at end of file diff --git a/pages/admin/tools.md b/pages/admin/tools.md new file mode 100644 index 00000000..50c13d6d --- /dev/null +++ b/pages/admin/tools.md @@ -0,0 +1,7 @@ +--- +title: Grav Tools + +access: + admin.tools: true + admin.super: true +--- diff --git a/themes/grav/css-compiled/template.css b/themes/grav/css-compiled/template.css index a797cbdc..6b5cca2e 100644 --- a/themes/grav/css-compiled/template.css +++ b/themes/grav/css-compiled/template.css @@ -3980,4 +3980,4 @@ button.toast-close-button { #admin-main #notifications .badge.alert i, #admin-main #notifications .sidebar-open #admin-sidebar #admin-menu li .badges .alert.updates i, .sidebar-open #admin-sidebar #admin-menu li .badges #admin-main #notifications .alert.updates i, #admin-main #notifications .gpm .alert.gpm-testing i, .gpm #admin-main #notifications .alert.gpm-testing i { margin-right: 3px; } -/*# sourceMappingURL=../css-compiled/template.css.map */ \ No newline at end of file +/*# sourceMappingURL=../css-compiled/template.css.map */ diff --git a/themes/grav/scss/template/_admin.scss b/themes/grav/scss/template/_admin.scss index 046bca1d..5ce099c7 100644 --- a/themes/grav/scss/template/_admin.scss +++ b/themes/grav/scss/template/_admin.scss @@ -1086,3 +1086,14 @@ body.sidebar-quickopen #admin-main { .pointer-events-disabled { pointer-events: none; } + +// Direct install + +.direct-install-content { + padding: 30px; + + .button { + margin-top: 10px; + margin-bottom: 50px; + } +} diff --git a/themes/grav/templates/partials/nav.html.twig b/themes/grav/templates/partials/nav.html.twig index b59b7540..7cfb5b9e 100644 --- a/themes/grav/templates/partials/nav.html.twig +++ b/themes/grav/templates/partials/nav.html.twig @@ -1,8 +1,9 @@ {% if authorize(['admin.login', 'admin.super']) %}