clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
name: farmOS Settings
description: Provides settings pages for core farmOS configuration options.
type: module
package: farmOS
core_version_requirement: ^10
dependencies:
- farm:farm_setup

View File

@@ -0,0 +1,13 @@
farm.setup.modules:
title: Modules
description: Select the core and community farmOS modules that you would like to be installed.
parent: farm.setup
route_name: farm_settings.modules_form
weight: 95
farm.settings:
title: Settings
description: Configure settings for farmOS and installed modules.
parent: farm.setup
route_name: farm_settings.settings_page
weight: 100

View File

@@ -0,0 +1,5 @@
farm_settings.settings_page:
base_route: farm_settings.settings_page
route_name: farm_settings.settings_page
title: 'Farm Info'
weight: -5

View File

@@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains farm_settings.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function farm_settings_help($route_name, RouteMatchInterface $route_match) {
$output = '';
// Modules form.
if ($route_name == 'farm_settings.modules_form') {
$output .= '<p>' . t('Select the core and community farmOS modules that you would like to be installed.') . '</p>';
}
return $output;
}

View File

@@ -0,0 +1,2 @@
administer farm settings:
title: 'Administer farmOS settings'

View File

@@ -0,0 +1,15 @@
<?php
/**
* @file
* Post update functions for farm_settings module.
*/
/**
* Install farmOS Setup module.
*/
function farm_settings_post_update_install_farm_setup(&$sandbox = NULL) {
if (!\Drupal::service('module_handler')->moduleExists('farm_setup')) {
\Drupal::service('module_installer')->install(['farm_setup']);
}
}

View File

@@ -0,0 +1,15 @@
farm_settings.settings_page:
path: '/farm/settings'
defaults:
_title: 'farmOS Settings'
_form: 'Drupal\farm_settings\Form\FarmSettingsFarmInfoForm'
requirements:
_permission: 'administer farm settings'
farm_settings.modules_form:
path: '/setup/modules'
defaults:
_title: 'Modules'
_form: 'Drupal\farm_settings\Form\FarmSettingsModulesForm'
requirements:
_permission: 'administer farm settings'

View File

@@ -0,0 +1,104 @@
<?php
namespace Drupal\farm_settings\Form;
use Drupal\Core\Datetime\TimeZoneFormHelper;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Form for configuring basic farm info.
*
* @ingroup farm
*/
class FarmSettingsFarmInfoForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'farm_settings_farm_info';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'system.date',
'system.site',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Set the form title.
$form['#title'] = $this->t('Configure Farm Info');
// Get the system.site config.
$site = $this->config('system.site');
// Textfield to edit site name.
$form['site_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Farm name'),
'#default_value' => $site->get('name'),
'#maxlength' => 128,
'#required' => TRUE,
];
// Get the system.date config.
$system_date = $this->config('system.date');
// Get list of timezones.
$timezones = TimeZoneFormHelper::getOptionsList();
// Dropdown to select default timezone.
$form['default_timezone'] = [
'#type' => 'select',
'#title' => $this->t('Default timezone'),
'#description' => $this->t('The default timezone of the farmOS server. Note that users can configure individual timezones later.'),
'#options' => $timezones,
'#default_value' => $system_date->get('timezone.default'),
'#required' => TRUE,
];
// Submit button.
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Get the submitted site name.
$site_name = $form_state->getvalue('site_name');
// Update system.site config.
$this->configFactory->getEditable('system.site')
->set('name', $site_name)
->save();
// Get the submitted timezone.
$default_timezone = $form_state->getValue('default_timezone');
// Update system.date config.
$this->configFactory->getEditable('system.date')
->set('timezone.default', $default_timezone)
->save();
// Display message from parent submitForm.
parent::submitForm($form, $form_state);
}
}

View File

@@ -0,0 +1,262 @@
<?php
namespace Drupal\farm_settings\Form;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form for installing farmOS modules.
*
* @ingroup farm
*/
class FarmSettingsModulesForm extends FormBase {
/**
* The package name for farmOS contrib modules.
*
* @var string
*/
const FARM_CONTRIB_PACKAGE = 'farmOS Contrib';
/**
* The package name for farmOS quick form modules.
*
* @var string
*/
const FARM_QUICK_PACKAGE = 'farmOS Quick Forms';
/**
* The module extension list.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleExtensionList;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'farm_settings_modules_form';
}
/**
* Constructs a new FarmSettingsModulesForm.
*
* @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
* The module extension list.
*/
public function __construct(ModuleExtensionList $module_extension_list) {
$this->moduleExtensionList = $module_extension_list;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('extension.list.module'),
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Set the form title.
$form['#title'] = $this->t('Install modules');
$form['#tree'] = TRUE;
// Core modules.
$form['core'] = [
'#type' => 'details',
'#title' => $this->t('Core modules'),
'#open' => TRUE,
];
// Contrib modules.
$form['contrib'] = [
'#type' => 'details',
'#title' => $this->t('Community modules'),
'#open' => TRUE,
];
// Quick form modules.
$form['quick'] = [
'#type' => 'details',
'#title' => $this->t('Quick form modules'),
'#open' => TRUE,
];
// Submit button.
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#name' => 'install-modules',
'#value' => $this->t('Install modules'),
];
// Load module options.
$modules = $this->moduleOptions();
// Build checkboxes for module options.
foreach ($modules as $type => $options) {
// Hide the fieldset if no modules are found.
if (empty($options['options'])) {
$form[$type]['#access'] = FALSE;
continue;
}
// Build checkboxes.
$form[$type]['modules'] = [
'#title' => $this->t('farmOS Modules'),
'#title_display' => 'invisible',
'#type' => 'container',
// form-checkboxes class is required so gin does not render each
// checkbox as a toggle element.
'#attributes' => [
'class' => ['form-checkboxes'],
],
];
// Add a checkbox for each module.
foreach ($options['options'] as $module => $module_info) {
$form[$type]['modules'][$module] = [
'#type' => 'checkbox',
'#title' => $module_info['name'],
'#description' => $module_info['description'],
'#default_value' => in_array($module, $options['default']),
];
}
// Disable checkboxes for modules marked as disabled.
foreach ($options['disabled'] as $name) {
$form[$type]['modules'][$name]['#disabled'] = TRUE;
}
}
return $form;
}
/**
* Helper function for building a list of modules to install.
*
* @return array
* Returns an array with two sub-arrays: `core` and `contrib`. Each of
* these includes three sub-arrays: 'options', 'default' and 'disabled'.
* All modules should be included in the 'options' array. Default modules
* will be selected for installation by default, and disabled modules
* cannot have their checkbox changed by users.
*/
protected function moduleOptions() {
// Reload the module list.
$this->moduleExtensionList->reset();
// Start an array of options for core and contrib modules.
$options = [
'core' => [],
'contrib' => [],
'quick' => [],
];
// Build core module options.
$modules = farm_modules();
$core_modules = array_merge($modules['default'], $modules['optional']);
// Load information about all modules.
$all_module_info = $this->moduleExtensionList->getAllAvailableInfo();
// Iterate through core modules and build options with name and description.
foreach ($core_modules as $module => $module_name) {
$options['core']['options'][$module] = [
'name' => $all_module_info[$module]['name'],
'description' => $all_module_info[$module]['description'] ?? NULL,
];
}
// Build contrib module options.
$contrib_modules = array_filter($all_module_info, function ($module_info) {
return isset($module_info['package']) && $module_info['package'] === static::FARM_CONTRIB_PACKAGE;
});
$options['contrib']['options'] = array_map(function ($module_info) {
return [
'name' => $module_info['name'],
'description' => $module_info['description'] ?? NULL,
];
}, $contrib_modules);
// Build quick form module options.
$quick_modules = array_filter($all_module_info, function ($module_info) {
return isset($module_info['package']) && $module_info['package'] === static::FARM_QUICK_PACKAGE;
});
$options['quick']['options'] = array_map(function ($module_info) {
return [
'name' => $module_info['name'],
'description' => $module_info['description'] ?? NULL,
];
}, $quick_modules);
// Check and disable modules that are installed.
$all_installed_modules = $this->moduleExtensionList->getAllInstalledInfo();
foreach (['core', 'contrib', 'quick'] as $option_key) {
$installed_modules = array_keys(array_intersect_key($options[$option_key]['options'], $all_installed_modules));
$options[$option_key]['default'] = $installed_modules;
$options[$option_key]['disabled'] = $installed_modules;
}
return $options;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Load the list of modules that should be installed from form_state.
$core_modules = array_filter($form_state->getValue(['core', 'modules'], []));
$contrib_modules = array_filter($form_state->getValue(['contrib', 'modules'], []));
$quick_modules = array_filter($form_state->getValue(['quick', 'modules'], []));
$selected_modules = array_merge($core_modules, $contrib_modules, $quick_modules);
// Filter out installed modules.
$all_installed_modules = $this->moduleExtensionList->getAllInstalledInfo();
$to_install = array_diff_key($selected_modules, $all_installed_modules);
// Bail if no modules need to be installed.
if (empty($to_install)) {
return;
}
// Assemble the batch operation for installing modules.
$operations = [];
foreach ($to_install as $module => $weight) {
$operations[] = [
[__NAMESPACE__ . '\FarmSettingsModulesForm', 'farmInstallModuleBatch'],
[$module, $this->moduleExtensionList->getName($module)],
];
}
$batch = [
'operations' => $operations,
'title' => $this->t('Installing farmOS modules'),
'error_message' => $this->t('The installation has encountered an error.'),
];
batch_set($batch);
}
/**
* Implements callback_batch_operation().
*
* Performs batch installation of farmOS modules.
*/
public static function farmInstallModuleBatch($module, $module_name, &$context) {
\Drupal::service('module_installer')->install([$module], TRUE);
$context['results'][] = $module;
$context['message'] = t('Installed %module module.', ['%module' => $module_name]);
}
}

View File

@@ -0,0 +1,8 @@
name: farmOS Settings Test
description: 'Support module for farm settings testing.'
type: module
package: farmOS Contrib
core_version_requirement: ^10
dependencies:
# This dependency is just to test installation of core module dependencies.
- farm:farm_maintenance

View File

@@ -0,0 +1,150 @@
<?php
namespace Drupal\Tests\farm_settings\Functional;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests installing modules via the module settings form.
*
* @group farm
*
* @see \Drupal\farm_settings\Form\FarmSettingsModulesForm
*/
class ModulesFormTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
protected $profile = 'farm';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'farm_settings',
'farm_land',
'farm_observation',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
$GLOBALS['farm_test'] = TRUE;
parent::setUp();
// Login a user with administer farm settings permission.
$user = $this->createUser(['administer farm settings']);
$this->drupalLogin($user);
}
/**
* Tests the install functionality of the module settings form.
*/
public function testInstallFunctionality() {
// Request the module settings page.
$this->drupalGet('setup/modules');
// Assert that installed modules are checked and disabled.
foreach (['farm_land', 'farm_observation'] as $module) {
$this->assertModuleCheckboxState('core', $module, TRUE, TRUE);
};
// Assert that uninstalled modules are unchecked.
foreach (['farm_plant', 'farm_maintenance'] as $module) {
$this->assertModuleCheckboxState('core', $module, FALSE, FALSE);
}
// Assert that the test module is uninstalled.
$this->assertModuleCheckboxState('contrib', 'farm_settings_test', FALSE, FALSE);
// Install the farm_plant and farm_settings_test modules.
$this->installModules([
'core' => ['farm_plant'],
'contrib' => ['farm_settings_test'],
]);
// Ensure farm_maintenance installed as farm_settings_test depends on it.
$this->assertModuleCheckboxState('core', 'farm_maintenance', TRUE, TRUE);
}
/**
* Helper function to assert the state of module checkboxes.
*
* @param string $type
* The module type. Core or contrib.
* @param string $module
* The module name.
* @param bool $checked
* Boolean if the checkbox should be checked. Defaults to FALSE.
* @param bool $disabled
* Boolean if the checkbox should be disabled. Defaults to FALSE.
*/
protected function assertModuleCheckboxState(string $type, string $module, bool $checked = FALSE, bool $disabled = FALSE) {
$page = $this->getSession()->getPage();
$field_name = $type . "[modules][$module]";
$checkbox = $page->findField($field_name);
$this->assertNotEmpty($checkbox, "The checkbox for $module exists.");
$this->assertEquals($checked, $checkbox->isChecked(), "The $module checkbox is " . $checked ? '' : 'not ' . 'checked.');
$this->assertEquals($disabled, $checkbox->hasAttribute('disabled'), "The $module checkbox is disabled: $disabled");
}
/**
* Helper function to test installing a list of modules.
*
* @param array $modules
* The array of modules to install. Expects arrays of module names keyed
* by the module type.
*/
protected function installModules(array $modules) {
// Get the current page.
$page = $this->getSession()->getPage();
// Loop through module types, core or contrib.
$this->assertNotEmpty($modules, 'Modules array is not empty.');
foreach ($modules as $type => $module_list) {
// Check each module in the list.
$this->assertNotEmpty($module_list, 'Modules of the specified type are provided.');
foreach ($module_list as $module_name) {
$page->checkField($type . "[modules][$module_name]");
$this->assertModuleCheckboxState($type, $module_name, TRUE, FALSE);
}
}
// Submit the form.
$page->pressButton('install-modules');
// Wait for the batch process to complete.
$this->assertSession()->waitForText('Install modules', 30000);
// Rebuild the list of installed modules.
$this->rebuildContainer();
/** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
$module_extension_list = \Drupal::service('extension.list.module');
$module_extension_list->reset();
// Assert that each module was installed and the form was updated.
foreach ($modules as $type => $module_list) {
foreach ($module_list as $module_name) {
// This method raises an error if the module is not installed.
$module_info = $module_extension_list->getExtensionInfo($module_name);
$this->assertNotEmpty($module_info);
// Assert that the checkbox is checked and disabled.
$this->assertModuleCheckboxState($type, $module_name, TRUE, TRUE);
}
}
}
}