cloud_orchestrator-3.0.0-alpha2/src/Installer/Form/ModuleConfigureForm.php
src/Installer/Form/ModuleConfigureForm.php
<?php
namespace Drupal\cloud_orchestrator\Installer\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleInstallerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Locale\CountryManager;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Routing\RouteBuilderInterface;
use Drupal\Core\Url;
use Drupal\cloud\Service\CloudServiceInterface;
use Drupal\cloud\Traits\CloudFormTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Additional Cloud Orchestrator related configurations.
*/
class ModuleConfigureForm extends ConfigFormBase {
use CloudFormTrait;
/**
* Drupal\Core\Messenger\MessengerInterface definition.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Drupal\Core\Config\ConfigFactoryInterface definition.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Drupal module installer.
*
* @var \Drupal\Core\Extension\ModuleInstallerInterface
*/
protected $moduleInstaller;
/**
* Route builder.
*
* @var \Drupal\Core\Routing\RouteBuilderInterface
*/
protected $routeBuilder;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The cloud service.
*
* @var \Drupal\cloud\Service\CloudServiceInterface
*/
protected $cloud;
/**
* Module configuration form constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* Config factory.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messanger service.
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
* The module installer service.
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
* The route builder service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
* @param \Drupal\cloud\Service\CloudServiceInterface $cloud
* The cloud service.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
* The typed config manager.
*/
public function __construct(
ConfigFactoryInterface $config_factory,
MessengerInterface $messenger,
ModuleInstallerInterface $module_installer,
RouteBuilderInterface $route_builder,
EntityTypeManagerInterface $entity_type_manager,
CloudServiceInterface $cloud,
TypedConfigManagerInterface $typed_config_manager,
) {
parent::__construct($config_factory, $typed_config_manager);
$this->messenger = $messenger;
$this->moduleInstaller = $module_installer;
$this->routeBuilder = $route_builder;
$this->entityTypeManager = $entity_type_manager;
$this->cloud = $cloud;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('messenger'),
$container->get('module_installer'),
$container->get('router.builder'),
$container->get('entity_type.manager'),
$container->get('cloud'),
$container->get('config.typed')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'cloud_orchestrator_module_configure_form';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames(): array {
return [];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$form = parent::buildForm($form, $form_state);
$form['#title'] = 'Additional configurations';
// Mock checkboxes showing required providers.
$form['required_providers'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Enabled Cloud Service Providers'),
'#options' => [
'aws_cloud' => $this->t('AWS'),
'k8s' => $this->t('K8s'),
'openstack' => $this->t('OpenStack'),
'vmware' => $this->t('VMware'),
'terraform' => $this->t('Terraform'),
],
'#default_value' => [
'aws_cloud',
'k8s',
'openstack',
'vmware',
'terraform',
],
'#description' => $this->t('These cloud service providers are enabled by default'),
'#disabled' => TRUE,
];
$form['install_ldap'] = [
'#type' => 'checkbox',
'#title' => $this->t('Install LDAP modules'),
'#description' => $this->t('Install LDAP modules to authenticate with Active Directory. LDAP can also be installed at a later time.'),
];
$form['install_spa'] = [
'#type' => 'checkbox',
'#title' => $this->t('Use React single page application (SPA)'),
'#description' => $this->t('The React SPA is a javascript UI that interacts with Cloud Orchestrator.'),
'#default_value' => TRUE,
];
$form['spa'] = [
'#type' => 'fieldset',
'#title' => 'SPA settings',
'#states' => [
'visible' => [
':input[id=edit-install-spa]' => [
'checked' => TRUE,
],
],
],
];
$form['spa']['cloud_spa_key_directory'] = [
'#type' => 'textfield',
'#title' => $this->t('Directory for keys'),
'#description' => $this->t('This is the directory where the public and private keys will be stored. This <strong>SHOULD</strong> be located outside of your webroot to avoid making them public unintentionally. The directory should be writeable by the webserver.'),
];
global $base_url;
$form['spa']['cloud_spa_callback_url'] = [
'#type' => 'textfield',
'#title' => $this->t('Redirect URI'),
'#default_value' => $base_url . '/' . Url::fromRoute('cloud_dashboard.endpoint1', [
'parameter' => 'callback',
], [
'absolute' => TRUE,
])->getInternalPath(),
'#description' => $this->t('The URI the SPA client will redirect to when needed.'),
];
$form['location_map'] = [
'#type' => 'fieldset',
'#title' => $this->t('Location map'),
'#open' => TRUE,
];
$form['location_map']['explanation'] = [
'#type' => 'markup',
'#markup' => $this->t("Configure the homepage map's default location and zoom level."),
];
$form['location_map']['country'] = [
'#type' => 'select',
'#title' => $this->t('Country'),
// Add a blank option in case users do not want to select a country.
'#options' => array_merge([
'' => $this->t('-- Select a country --'),
], CountryManager::getStandardList()),
];
$form['location_map']['city'] = [
'#type' => 'textfield',
'#title' => $this->t('City'),
];
$form['location_map']['zoom_level'] = [
'#type' => 'select',
'#title' => $this->t('Zoom level'),
'#options' => [
'1' => $this->t('1'),
'2' => $this->t('2'),
'3' => $this->t('3'),
'4' => $this->t('4'),
'5' => $this->t('5'),
'6' => $this->t('6'),
'7' => $this->t('7'),
'8' => $this->t('8'),
'9' => $this->t('9'),
],
'#default_value' => '5',
];
$form['actions']['submit']['#value'] = $this->t('Save and continue');
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state): void {
// Clear errors before validating again. For some reason, errors are not
// cleared out if they have been corrected.
$this->messenger->deleteAll();
if ((bool) $form_state->getValue('install_spa') === FALSE) {
return;
}
// Check if the callback URL exists.
if (empty($form_state->getValue('cloud_spa_callback_url'))) {
$form_state->setError($form['spa']['cloud_spa_callback_url'], $this->t('Callback url is empty.'));
}
// Validate the key directory by using `isDirectory()`.
if (is_dir($form_state->getValue('cloud_spa_key_directory')) === FALSE) {
$form_state->setError($form['spa']['cloud_spa_key_directory'], $this->t('Private key directory is not valid. The directory should be the absolute path to a directory outside the webserver document root.'));
return;
}
// Check if the directory is writeable.
if (is_writable($form_state->getValue('cloud_spa_key_directory')) === FALSE) {
$form_state->setError($form['spa']['cloud_spa_key_directory'], $this->t('Private key directory is not writeable. The directory should be writeable by the webserver.'));
}
// Validate location map input.
$country = $form_state->getValue('country');
$city = $form_state->getValue('city');
if (!empty($country) && empty($city)) {
$form_state->setError($form['location_map']['city'], $this->t('Please specify a city name.'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$modules = [];
// Install any additional providers.
if ((bool) $form_state->getValue('install_ldap') === TRUE) {
// Add LDAP modules to install.
$modules = [
'ldap_user',
'ldap_servers',
'ldap_authorization',
'ldap_query',
'ldap_authorization',
'ldap_authentication',
'authorization',
'externalauth',
];
}
if (!empty($modules)) {
try {
$this->moduleInstaller->install($modules);
}
catch (\Exception $e) {
$this->messenger->addError($e->getMessage());
}
}
// Set spreadsheet feature to FALSE.
$this->configFactory
->getEditable('aws_cloud.settings')
->set('aws_cloud_instance_type_prices_spreadsheet', FALSE)
->save();
$install_spa = (bool) $form_state->getValue('install_spa');
// The $install_spa === TRUE sets up the proper public and private keys
// saves it to the simple_oauth.settings configuration object. Then it
// creates a oAuth consumer and sets it as default.
if ($install_spa === TRUE) {
// Enable the spa.
$this->enableSpaApp(
$form_state->getValue('cloud_spa_key_directory'),
$form_state->getValue('cloud_spa_callback_url')
);
}
// Set up the location map.
$this->setupLocationMap($form_state);
// We install some menu links, so we have to rebuild the router,
// to ensure the menu links are valid.
$this->routeBuilder->rebuildIfNeeded();
drupal_flush_all_caches();
}
/**
* Helper method to setup location map defaults.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
*/
private function setupLocationMap(FormStateInterface $form_state): void {
// Skip if geocoder is not available.
if ($this->cloud->isGeocoderAvailable() === FALSE) {
return;
}
$country = $form_state->getValue('country');
$city = $form_state->getValue('city');
$zoom_level = $form_state->getValue('zoom_level');
if (empty($country) || empty($city)) {
return;
}
$provider_id = $this->configFactory
->get('cloud.settings')
->get('cloud_location_geocoder_plugin');
if (empty($provider_id)) {
return;
}
try {
$provider = $this->entityTypeManager->getStorage('geocoder_provider')
->load($provider_id);
}
catch (\Exception $e) {
$this->messenger->addError($e->getMessage());
return;
}
$city = $form_state->getValue('city');
$country = $form_state->getValue('country');
$address = "$city $country";
// Call geocoder service without dependency injection as an error occurs
// when geocoder module does not exist.
// @codingStandardsIgnoreStart
$locations = \Drupal::service('geocoder')->geocode($address, [$provider]); // @phpstan-ignore-line
// @codingStandardsIgnoreEnd
if (empty($locations)) {
return;
}
$latitude = $locations->first()->getCoordinates()->getLatitude();
$longitude = $locations->first()->getCoordinates()->getLongitude();
$config = $this->configFactory()->getEditable('cloud_dashboard.settings');
$config->set('cloud_dashboard_location_map_country', $country);
$config->set('cloud_dashboard_location_map_city', $city);
$config->set('cloud_dashboard_location_map_latitude', $latitude);
$config->set('cloud_dashboard_location_map_longitude', $longitude);
$config->set('cloud_dashboard_location_map_zoom_level', $zoom_level);
$config->save();
}
}
