Skip to content

Commit

Permalink
MDL-70608 lang: Install langpacks asynchronously via ad hoc task
Browse files Browse the repository at this point in the history
When multiple language packs are selected for installation, perform the
installation asynchronously in the background via ad hoc task.
  • Loading branch information
mudrd8mz committed Feb 19, 2021
1 parent a93828a commit c85215e
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 7 deletions.
21 changes: 20 additions & 1 deletion admin/tool/langimport/classes/controller.php
Expand Up @@ -82,7 +82,7 @@ public function install_languagepacks($langs, $updating = false) {
$a->url = $this->installer->lang_pack_url($langcode);
$a->dest = $CFG->dataroot.'/lang';
$this->errors[] = get_string('remotedownloaderror', 'error', $a);
throw new \moodle_exception('remotedownloaderror', 'error', $a);
throw new \moodle_exception('remotedownloaderror', 'error', '', $a);
break;
case \lang_installer::RESULT_INSTALLED:
$updatedpacks++;
Expand Down Expand Up @@ -221,4 +221,23 @@ public function is_installed_lang($lang, $md5check) {
public function lang_pack_url($langcode = '') {
return $this->installer->lang_pack_url($langcode);
}

/**
* Schedule installation of the given language packs asynchronously via ad hoc task.
*
* @param string|array $langs array of langcodes or individual langcodes
*/
public function schedule_languagepacks_installation($langs): void {
global $USER;

$task = new \tool_langimport\task\install_langpacks();
$task->set_userid($USER->id);
$task->set_custom_data([
'langs' => $langs,
]);

\core\task\manager::queue_adhoc_task($task, true);

$this->info[] = get_string('installscheduled', 'tool_langimport');
}
}
109 changes: 109 additions & 0 deletions admin/tool/langimport/classes/task/install_langpacks.php
@@ -0,0 +1,109 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace tool_langimport\task;

/**
* Ad hoc task to install one or more language packs.
*
* @package tool_langimport
* @category task
* @copyright 2021 David Mudrák <david@moodle.com>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class install_langpacks extends \core\task\adhoc_task {

/**
* Execute the ad hoc task.
*/
public function execute(): void {

$data = $this->get_custom_data();

if (empty($data->langs)) {
mtrace('No language packs to install');
}

get_string_manager()->reset_caches();

$controller = new \tool_langimport\controller();

\core_php_time_limit::raise();

try {
$controller->install_languagepacks($data->langs);
$this->notify_user_success($controller);

} catch (\Throwable $e) {
$this->notify_user_error($e->getMessage());

} finally {
get_string_manager()->reset_caches();
}
}

/**
* Notify user that the task finished successfully.
*
* @param \tool_langimport\controller $controller
*/
protected function notify_user_success(\tool_langimport\controller $controller): void {

$message = new \core\message\message();

$message->component = 'moodle';
$message->name = 'notices';
$message->userfrom = \core_user::get_noreply_user();
$message->userto = $this->get_userid();
$message->notification = 1;
$message->contexturl = (new \moodle_url('/admin/tool/langimport/index.php'))->out(false);
$message->contexturlname = get_string('pluginname', 'tool_langimport');

$message->subject = get_string('installfinished', 'tool_langimport');
$message->fullmessage = '* ' . implode(PHP_EOL . '* ', $controller->info);
$message->fullmessageformat = FORMAT_MARKDOWN;
$message->fullmessagehtml = markdown_to_html($message->fullmessage);
$message->smallmessage = get_string('installfinished', 'tool_langimport');

message_send($message);
}

/**
* Notify user that the task failed.
*
* @param string $error The error text
*/
protected function notify_user_error(string $error): void {

$message = new \core\message\message();

$message->component = 'moodle';
$message->name = 'notices';
$message->userfrom = \core_user::get_noreply_user();
$message->userto = $this->get_userid();
$message->notification = 1;
$message->contexturl = (new \moodle_url('/admin/tool/langimport/index.php'))->out(false);
$message->contexturlname = get_string('pluginname', 'tool_langimport');

$message->subject = get_string('installfailed', 'tool_langimport');
$message->fullmessage = $error;
$message->fullmessageformat = FORMAT_PLAIN;
$message->fullmessagehtml = text_to_html($message->fullmessage);
$message->smallmessage = get_string('installfailed', 'tool_langimport');

message_send($message);
}
}
20 changes: 18 additions & 2 deletions admin/tool/langimport/index.php
Expand Up @@ -66,8 +66,15 @@
$controller = new tool_langimport\controller();

if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($pack)) {
core_php_time_limit::raise();
$controller->install_languagepacks($pack);
if (is_array($pack) && count($pack) > 1) {
// Installing multiple languages can take a while - perform it asynchronously in the background.
$controller->schedule_languagepacks_installation($pack);

} else {
// Single language pack to be installed synchronously. It should be reasonably quick and can be used for debugging, too.
core_php_time_limit::raise();
$controller->install_languagepacks($pack);
}
}

if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($confirmtounistall))) {
Expand Down Expand Up @@ -159,6 +166,15 @@
\core\notification::error($info);
}

// Inform about pending language packs installations.
foreach (\core\task\manager::get_adhoc_tasks('\tool_langimport\task\install_langpacks') as $installtask) {
$installtaskdata = $installtask->get_custom_data();

if (!empty($installtaskdata->langs)) {
\core\notification::info(get_string('installpending', 'tool_langimport', implode(', ', $installtaskdata->langs)));
}
}

if ($missingparents) {
foreach ($missingparents as $l => $parent) {
$a = new stdClass();
Expand Down
4 changes: 4 additions & 0 deletions admin/tool/langimport/lang/en/tool_langimport.php
Expand Up @@ -25,6 +25,10 @@

$string['downloadnotavailable'] = 'Unable to connect to the download server. It is not possible to install or update the language packs automatically. Please download the appropriate ZIP file(s) from <a href="{$a->src}">{$a->src}</a> and unzip them manually to your data directory <code>{$a->dest}</code>';
$string['install'] = 'Install selected language pack(s)';
$string['installfailed'] = 'Language packs installation failed!';
$string['installfinished'] = 'Language packs installation finished.';
$string['installpending'] = 'The following language packs will be installed soon: {$a}.';
$string['installscheduled'] = 'Language packs scheduled for installation.';
$string['installedlangs'] = 'Installed language packs';
$string['langimport'] = 'Language import utility';
$string['langimportdisabled'] = 'Language import feature has been disabled. You have to update your language packs manually at the file-system level. Do not forget to purge string caches after you do so.';
Expand Down
28 changes: 24 additions & 4 deletions admin/tool/langimport/tests/behat/manage_langpacks.feature
Expand Up @@ -18,7 +18,22 @@ Feature: Manage language packs
And the "Installed language packs" select box should contain "en_ar"
And I navigate to "Reports > Live logs" in site administration
And I should see "The language pack 'en_ar' was installed."
And I log out

Scenario: Install multiple language packs asynchronously in the background
Given I log in as "admin"
And I navigate to "Language > Language packs" in site administration
And I set the field "Available language packs" to "en_us,en_us_k12"
When I press "Install selected language pack(s)"
Then I should see "Language packs scheduled for installation."
And I should see "The following language packs will be installed soon: en_us, en_us_k12."
And I trigger cron
And I am on homepage
And I navigate to "Language > Language packs" in site administration
And the "Installed language packs" select box should contain "en_us"
And the "Installed language packs" select box should contain "en_us_k12"
And I navigate to "Reports > Live logs" in site administration
And I should see "The language pack 'en_us' was installed."
And I should see "The language pack 'en_us_k12' was installed."

@javascript
Scenario: Search for available language pack
Expand All @@ -39,7 +54,14 @@ Feature: Manage language packs
And I should see "Language pack update completed"
And I navigate to "Reports > Live logs" in site administration
And I should see "The language pack 'en_ar' was updated."
And I log out

Scenario: Inform admin that there are multiple installed languages and updating them all can take too long
Given outdated langpack 'en_ar' is installed
And outdated langpack 'en_us' is installed
And outdated langpack 'en_us_k12' is installed
When I log in as "admin"
And I navigate to "Language > Language packs" in site administration
Then I should see "Updating all installed language packs by clicking the button can take a long time and lead to timeouts."

Scenario: Try to uninstall language pack
Given I log in as "admin"
Expand All @@ -55,7 +77,6 @@ Feature: Manage language packs
And I navigate to "Reports > Live logs" in site administration
And I should see "The language pack 'en_ar' was removed."
And I should see "Language pack uninstalled"
And I log out

Scenario: Try to uninstall English language pack
Given I log in as "admin"
Expand All @@ -65,4 +86,3 @@ Feature: Manage language packs
Then I should see "The English language pack cannot be uninstalled."
And I navigate to "Reports > Live logs" in site administration
And I should not see "Language pack uninstalled"
And I log out

0 comments on commit c85215e

Please sign in to comment.