Loading addtoany.module +85 −34 Original line number Diff line number Diff line Loading @@ -5,14 +5,14 @@ * Handle AddToAny integration. */ use Drupal\Core\Entity\EntityInterface; use Drupal\addtoany\Form\AddToAnySettingsForm; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Render\Markup; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; use Drupal\Component\Utility\UrlHelper; use Drupal\node\Entity\Node; use Drupal\addtoany\Form\AddToAnySettingsForm; /** * Implements hook_help(). Loading @@ -37,7 +37,6 @@ function addtoany_help($route_name, RouteMatchInterface $route_match){ } } /** * Implements hook_theme(). */ Loading Loading @@ -122,7 +121,8 @@ function addtoany_entity_extra_field_info() { $entityTypeId = $type->id(); $isAllowed = $config->get("entities.{$entityTypeId}"); if ($isAllowed) { $bundles = Drupal::service('entity_type.bundle.info')->getBundleInfo($entityTypeId); $bundles = Drupal::service('entity_type.bundle.info') ->getBundleInfo($entityTypeId); foreach ($bundles as $bundle => $bundle_data) { $extra[$entityTypeId][$bundle]['display']['addtoany'] = [ 'label' => t('AddToAny'), Loading Loading @@ -152,7 +152,8 @@ function addtoany_entity_view(array &$build, EntityInterface $entity, EntityView if ($isAllowed) { $data = addtoany_create_entity_data($entity); $build['addtoany'] = [ '#addtoany_html' => \Drupal::token()->replace($data['addtoany_html'], ['node' => $entity]), '#addtoany_html' => \Drupal::token() ->replace($data['addtoany_html'], ['node' => $entity]), '#link_url' => $data['link_url'], '#link_title' => $data['link_title'], '#button_setting' => $data['button_setting'], Loading Loading @@ -188,9 +189,14 @@ function addtoany_page_attachments(&$page) { } } //@TODO: Make path configurable. $version = \Drupal::state()->get('addtoany.scripts_version'); $addtoany_lib_path = \Drupal::service('file_url_generator') ->generateAbsoluteString('public://js/addtoany/menu/' . $version); $javascript_header = 'window.a2a_config=window.a2a_config||{};' . 'a2a_config.callbacks=[];a2a_config.overlays=[];' . 'a2a_config.templates={};' . 'a2a_config.static_server= ' . json_encode($addtoany_lib_path, JSON_UNESCAPED_SLASHES) . ';' . $additional_js; // Add AddToAny initial JS config. Loading Loading @@ -249,7 +255,8 @@ function addtoany_page_attachments(&$page) { * The array with url, title, additional_html that will be send to Twig. */ function addtoany_create_entity_data($node, $config = NULL) { $url = isset($node) ? $node->toUrl('canonical', ['absolute' => TRUE])->toString() : NULL; $url = isset($node) ? $node->toUrl('canonical', ['absolute' => TRUE]) ->toString() : NULL; $title = isset($node) ? $node->label() : NULL; return addtoany_create_data($url, $title, $config); } Loading Loading @@ -287,7 +294,9 @@ function addtoany_create_data($url = NULL, $title = NULL, $config = NULL) { $url = (is_null($url) || $url === $front_url . '/node') ? $front_url : $url; } // Use the current path if the URL is still NULL. $url = (is_null($url)) ? Url::fromRoute('<current>')->setAbsolute()->toString() : $url; $url = (is_null($url)) ? Url::fromRoute('<current>') ->setAbsolute() ->toString() : $url; } else { // Sanitize and encode URL for HTML output. Loading Loading @@ -346,3 +355,45 @@ function addtoany_create_data($url = NULL, $title = NULL, $config = NULL) { return $info; } /** * Implements hook_library_info_alter(). */ function addtoany_library_info_alter(&$libraries, $extension) { // Get the remote addtoany library and download it locally to the website. if ($extension == 'addtoany' && isset($libraries['addtoany']['js']['https://static.addtoany.com/menu/page.js'])) { if (\Drupal::config('addtoany.settings') ->get('library_location') == 'local') { $version = \Drupal::state()->get('addtoany.scripts_version'); $file = 'public://js/addtoany/menu/' . $version . 'page.js'; if (is_file($file)) { $fileUrl = \Drupal::service('file_url_generator') ->generateString($file); unset($libraries['addtoany']['js']['https://static.addtoany.com/menu/page.js']); $libraries['addtoany']['js'][$fileUrl] = []; } } } } /** * Implements hook_cache_flush(). */ function addtoany_cache_flush() { // Delete all the old versions of the scripts. \Drupal::service('addtoany.update')->cleanup(); } /** * Implements hook_cron(). */ function addtoany_cron() { $version = \Drupal::state()->get('addtoany.scripts_version'); $latest_version = \Drupal::service('addtoany.update')->getScripts(); // Do not update if latest version is already there. if ($latest_version['version'] !== $version) { // Update addtoany scripts locally. \Drupal::service('addtoany.update')->updateLatestScripts(); } } addtoany.services.yml 0 → 100644 +4 −0 Original line number Diff line number Diff line services: addtoany.update: class: Drupal\addtoany\UpdateScripts arguments: [ '@file_system', '@file_url_generator', '@logger.factory', '@state' ] src/Form/AddToAnySettingsForm.php +92 −68 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * Configure AddToAny settings for this site. */ class AddToAnySettingsForm extends ConfigFormBase { /** * Drupal\Core\Extension\ModuleHandler definition. * Loading Loading @@ -77,15 +78,6 @@ class AddToAnySettingsForm extends ConfigFormBase { return 'addtoany_settings_form'; } /** * {@inheritdoc} */ protected function getEditableConfigNames() { return [ 'addtoany.settings', ]; } /** * {@inheritdoc} */ Loading @@ -100,6 +92,11 @@ class AddToAnySettingsForm extends ConfigFormBase { $button_img = '<img src="' . $base_path . $this->moduleExtensionList->getPath('addtoany') . '/images/%s" width="%d" height="%d"%s />'; $library_options = [ 'remote' => $this->t('Remote'), 'local' => $this->t('Local'), ]; $button_options = [ 'default' => sprintf($button_img, 'a2a_32_32.svg', 32, 32, ' class="addtoany-round-icon"'), 'custom' => $this->t('Custom button'), Loading Loading @@ -191,6 +188,15 @@ class AddToAnySettingsForm extends ConfigFormBase { '#title' => $this->t('Additional options'), '#open' => ($js_value !== '' || $css_value !== '') ? TRUE : FALSE, ]; $form['addtoany_additional_settings']['addtoany_library_location'] = [ '#type' => 'radios', '#title' => $this->t('Location of the library'), '#description' => $this->t('The way the library is stored, if local than refreshed on cache clear'), '#default_value' => $addtoany_settings->get('library_location') ?? 'remote', '#options' => $library_options, ]; $form['addtoany_additional_settings']['addtoany_additional_js'] = [ '#type' => 'textarea', '#title' => $this->t('Additional JavaScript'), Loading Loading @@ -237,8 +243,14 @@ class AddToAnySettingsForm extends ConfigFormBase { // Whitelist the entity IDs that let us link to each bundle's Manage Display page. $linkableEntities = [ 'block_content', 'comment', 'commerce_product', 'commerce_store', 'contact_message', 'media', 'node', 'paragraph', 'block_content', 'comment', 'commerce_product', 'commerce_store', 'contact_message', 'media', 'node', 'paragraph', ]; foreach ($entities as $entity) { Loading Loading @@ -274,7 +286,7 @@ class AddToAnySettingsForm extends ConfigFormBase { '#title' => $this->t('@entity', ['@entity' => $entity->getLabel()]), '#default_value' => $addtoany_settings->get("entities.{$entityId}"), '#description' => $description, '#attributes' => ['class' => ['addtoany-entity-checkbox']] '#attributes' => ['class' => ['addtoany-entity-checkbox']], ]; } Loading @@ -287,6 +299,24 @@ class AddToAnySettingsForm extends ConfigFormBase { return parent::buildForm($form, $form_state); } /** * Get all available content entities in the environment. * * @return array */ public static function getContentEntities() { $content_entity_types = []; $entity_type_definitions = \Drupal::entityTypeManager()->getDefinitions(); /* @var $definition EntityTypeInterface */ foreach ($entity_type_definitions as $definition) { if ($definition instanceof ContentEntityType) { $content_entity_types[] = $definition; } } return $content_entity_types; } /** * {@inheritdoc} */ Loading @@ -299,7 +329,8 @@ class AddToAnySettingsForm extends ConfigFormBase { ->set('buttons_size', $values['addtoany_buttons_size']) ->set('custom_universal_button', $values['addtoany_custom_universal_button']) ->set('universal_button', $values['addtoany_universal_button']) ->set('universal_button_placement', $values['addtoany_universal_button_placement']); ->set('universal_button_placement', $values['addtoany_universal_button_placement']) ->set('library_location', $values['addtoany_library_location']); foreach (self::getContentEntities() as $entity) { $entityId = $entity->id(); Loading @@ -313,19 +344,12 @@ class AddToAnySettingsForm extends ConfigFormBase { } /** * Get all available content entities in the environment. * @return array * {@inheritdoc} */ public static function getContentEntities() { $content_entity_types = []; $entity_type_definitions = \Drupal::entityTypeManager()->getDefinitions(); /* @var $definition EntityTypeInterface */ foreach ($entity_type_definitions as $definition) { if ($definition instanceof ContentEntityType) { $content_entity_types[] = $definition; } protected function getEditableConfigNames() { return [ 'addtoany.settings', ]; } return $content_entity_types; } } src/UpdateScripts.php 0 → 100644 +169 −0 Original line number Diff line number Diff line <?php namespace Drupal\addtoany; use Drupal\Core\File\FileUrlGeneratorInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\File\FileSystemInterface; /** * Class UpdateScripts */ class UpdateScripts { /** * Path to contract files. */ const scriptsPath = 'public://js/addtoany/menu/'; /** * List of the latest scripts to download. */ const latestScripts = 'https://www.addtoany.com/ext/updater/files_list/'; /** * The file system service. * * @var \Drupal\Core\File\FileSystemInterface */ protected $fileSystem; /** * The file URL generator. * * @var \Drupal\Core\File\FileUrlGeneratorInterface */ protected $fileUrlGenerator; /** * Logger channel. * * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface */ protected $logger; /** * The state service. * * @var \Drupal\Core\State\StateInterface */ protected $state; /** * Constructs a UpdateScripts object * * @param \Drupal\Core\File\FileSystemInterface $fileSystem * @param \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger * @param \Drupal\Core\State\StateInterface $state * */ public function __construct(FileSystemInterface $fileSystem, FileUrlGeneratorInterface $fileUrlGenerator, LoggerChannelFactoryInterface $logger, StateInterface $state) { $this->fileSystem = $fileSystem; $this->logger = $logger->get('addtoany'); $this->fileUrlGenerator = $fileUrlGenerator; $this->state = $state; } /** * Download the latest scripts. * * @see https://www.addtoany.com/ext/updater/files_list * @return false|void */ public function updateLatestScripts() { try { // List of files that will be downloaded with version. $files_to_download = $this->getScripts(); // Create directory for output $directory = self::scriptsPath . $files_to_download['version']; // Now we only need the files that will be downloaded. $latest_version = $files_to_download['version']; unset($files_to_download['version']); // Empty the directory before putting new content. //$this->fileSystem->deleteRecursive($directory); if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) { throw new \RuntimeException("Failed to create the directory: " . $directory); } foreach ($files_to_download as $file_to_download) { $content = file_get_contents($file_to_download); $name = basename($file_to_download); $file = $directory . '/' . $name; // Remove hardcoded external link in page.js that downloads information document.. if ($name == 'page.js') { preg_match('#https?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s])(.html)[-A-Za-z0-9+&@\#/%?=~_|!:,.;]+[-A-Za-z0-9+&@\#/%=~_|])#', $content, $match); $content = str_replace($match[0], '', $content); } file_put_contents($file, $content); } $this->state->set('addtoany.scripts_version', $latest_version); } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to update addtoany scripts\n", ); return FALSE; } } /** * Get a list of the latest script files * and use the hash in the file names for versioning. * * @return array|false */ public function getScripts() { try { $files_to_download = file_get_contents(self::latestScripts); $files_to_download = explode("\r\n", $files_to_download, 20); // Take the first file and extract // the hash in the name and use it for versioning. $first_file = reset($files_to_download); $file_name_parts = explode('.', basename($first_file)); $version_hash = $file_name_parts[1]; if (empty($version_hash)) { throw new \RuntimeException("Failed to get the hash from js file name: " . basename($first_file)); } $files_to_download['version'] = $version_hash; return $files_to_download; } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to get the scripts\n", ); return FALSE; } } /** * Remove all the versions of the scripts * except the latest version. * * @return void * @see getScripts() to check how versioning is done. */ public function cleanup() { try { $all_script_versions = $this->fileSystem->scanDirectory(self::scriptsPath, '/.*/', ['recurse' => FALSE]); $latest_version = $this->state->get('addtoany.scripts_version'); if (isset($all_script_versions)) { foreach ($all_script_versions as $script_version) { if ($script_version->name === $latest_version) { continue; } $this->fileSystem->deleteRecursive($script_version->uri); } } } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to cleanup old scripts\n", ); } } } Loading
addtoany.module +85 −34 Original line number Diff line number Diff line Loading @@ -5,14 +5,14 @@ * Handle AddToAny integration. */ use Drupal\Core\Entity\EntityInterface; use Drupal\addtoany\Form\AddToAnySettingsForm; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Render\Markup; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; use Drupal\Component\Utility\UrlHelper; use Drupal\node\Entity\Node; use Drupal\addtoany\Form\AddToAnySettingsForm; /** * Implements hook_help(). Loading @@ -37,7 +37,6 @@ function addtoany_help($route_name, RouteMatchInterface $route_match){ } } /** * Implements hook_theme(). */ Loading Loading @@ -122,7 +121,8 @@ function addtoany_entity_extra_field_info() { $entityTypeId = $type->id(); $isAllowed = $config->get("entities.{$entityTypeId}"); if ($isAllowed) { $bundles = Drupal::service('entity_type.bundle.info')->getBundleInfo($entityTypeId); $bundles = Drupal::service('entity_type.bundle.info') ->getBundleInfo($entityTypeId); foreach ($bundles as $bundle => $bundle_data) { $extra[$entityTypeId][$bundle]['display']['addtoany'] = [ 'label' => t('AddToAny'), Loading Loading @@ -152,7 +152,8 @@ function addtoany_entity_view(array &$build, EntityInterface $entity, EntityView if ($isAllowed) { $data = addtoany_create_entity_data($entity); $build['addtoany'] = [ '#addtoany_html' => \Drupal::token()->replace($data['addtoany_html'], ['node' => $entity]), '#addtoany_html' => \Drupal::token() ->replace($data['addtoany_html'], ['node' => $entity]), '#link_url' => $data['link_url'], '#link_title' => $data['link_title'], '#button_setting' => $data['button_setting'], Loading Loading @@ -188,9 +189,14 @@ function addtoany_page_attachments(&$page) { } } //@TODO: Make path configurable. $version = \Drupal::state()->get('addtoany.scripts_version'); $addtoany_lib_path = \Drupal::service('file_url_generator') ->generateAbsoluteString('public://js/addtoany/menu/' . $version); $javascript_header = 'window.a2a_config=window.a2a_config||{};' . 'a2a_config.callbacks=[];a2a_config.overlays=[];' . 'a2a_config.templates={};' . 'a2a_config.static_server= ' . json_encode($addtoany_lib_path, JSON_UNESCAPED_SLASHES) . ';' . $additional_js; // Add AddToAny initial JS config. Loading Loading @@ -249,7 +255,8 @@ function addtoany_page_attachments(&$page) { * The array with url, title, additional_html that will be send to Twig. */ function addtoany_create_entity_data($node, $config = NULL) { $url = isset($node) ? $node->toUrl('canonical', ['absolute' => TRUE])->toString() : NULL; $url = isset($node) ? $node->toUrl('canonical', ['absolute' => TRUE]) ->toString() : NULL; $title = isset($node) ? $node->label() : NULL; return addtoany_create_data($url, $title, $config); } Loading Loading @@ -287,7 +294,9 @@ function addtoany_create_data($url = NULL, $title = NULL, $config = NULL) { $url = (is_null($url) || $url === $front_url . '/node') ? $front_url : $url; } // Use the current path if the URL is still NULL. $url = (is_null($url)) ? Url::fromRoute('<current>')->setAbsolute()->toString() : $url; $url = (is_null($url)) ? Url::fromRoute('<current>') ->setAbsolute() ->toString() : $url; } else { // Sanitize and encode URL for HTML output. Loading Loading @@ -346,3 +355,45 @@ function addtoany_create_data($url = NULL, $title = NULL, $config = NULL) { return $info; } /** * Implements hook_library_info_alter(). */ function addtoany_library_info_alter(&$libraries, $extension) { // Get the remote addtoany library and download it locally to the website. if ($extension == 'addtoany' && isset($libraries['addtoany']['js']['https://static.addtoany.com/menu/page.js'])) { if (\Drupal::config('addtoany.settings') ->get('library_location') == 'local') { $version = \Drupal::state()->get('addtoany.scripts_version'); $file = 'public://js/addtoany/menu/' . $version . 'page.js'; if (is_file($file)) { $fileUrl = \Drupal::service('file_url_generator') ->generateString($file); unset($libraries['addtoany']['js']['https://static.addtoany.com/menu/page.js']); $libraries['addtoany']['js'][$fileUrl] = []; } } } } /** * Implements hook_cache_flush(). */ function addtoany_cache_flush() { // Delete all the old versions of the scripts. \Drupal::service('addtoany.update')->cleanup(); } /** * Implements hook_cron(). */ function addtoany_cron() { $version = \Drupal::state()->get('addtoany.scripts_version'); $latest_version = \Drupal::service('addtoany.update')->getScripts(); // Do not update if latest version is already there. if ($latest_version['version'] !== $version) { // Update addtoany scripts locally. \Drupal::service('addtoany.update')->updateLatestScripts(); } }
addtoany.services.yml 0 → 100644 +4 −0 Original line number Diff line number Diff line services: addtoany.update: class: Drupal\addtoany\UpdateScripts arguments: [ '@file_system', '@file_url_generator', '@logger.factory', '@state' ]
src/Form/AddToAnySettingsForm.php +92 −68 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * Configure AddToAny settings for this site. */ class AddToAnySettingsForm extends ConfigFormBase { /** * Drupal\Core\Extension\ModuleHandler definition. * Loading Loading @@ -77,15 +78,6 @@ class AddToAnySettingsForm extends ConfigFormBase { return 'addtoany_settings_form'; } /** * {@inheritdoc} */ protected function getEditableConfigNames() { return [ 'addtoany.settings', ]; } /** * {@inheritdoc} */ Loading @@ -100,6 +92,11 @@ class AddToAnySettingsForm extends ConfigFormBase { $button_img = '<img src="' . $base_path . $this->moduleExtensionList->getPath('addtoany') . '/images/%s" width="%d" height="%d"%s />'; $library_options = [ 'remote' => $this->t('Remote'), 'local' => $this->t('Local'), ]; $button_options = [ 'default' => sprintf($button_img, 'a2a_32_32.svg', 32, 32, ' class="addtoany-round-icon"'), 'custom' => $this->t('Custom button'), Loading Loading @@ -191,6 +188,15 @@ class AddToAnySettingsForm extends ConfigFormBase { '#title' => $this->t('Additional options'), '#open' => ($js_value !== '' || $css_value !== '') ? TRUE : FALSE, ]; $form['addtoany_additional_settings']['addtoany_library_location'] = [ '#type' => 'radios', '#title' => $this->t('Location of the library'), '#description' => $this->t('The way the library is stored, if local than refreshed on cache clear'), '#default_value' => $addtoany_settings->get('library_location') ?? 'remote', '#options' => $library_options, ]; $form['addtoany_additional_settings']['addtoany_additional_js'] = [ '#type' => 'textarea', '#title' => $this->t('Additional JavaScript'), Loading Loading @@ -237,8 +243,14 @@ class AddToAnySettingsForm extends ConfigFormBase { // Whitelist the entity IDs that let us link to each bundle's Manage Display page. $linkableEntities = [ 'block_content', 'comment', 'commerce_product', 'commerce_store', 'contact_message', 'media', 'node', 'paragraph', 'block_content', 'comment', 'commerce_product', 'commerce_store', 'contact_message', 'media', 'node', 'paragraph', ]; foreach ($entities as $entity) { Loading Loading @@ -274,7 +286,7 @@ class AddToAnySettingsForm extends ConfigFormBase { '#title' => $this->t('@entity', ['@entity' => $entity->getLabel()]), '#default_value' => $addtoany_settings->get("entities.{$entityId}"), '#description' => $description, '#attributes' => ['class' => ['addtoany-entity-checkbox']] '#attributes' => ['class' => ['addtoany-entity-checkbox']], ]; } Loading @@ -287,6 +299,24 @@ class AddToAnySettingsForm extends ConfigFormBase { return parent::buildForm($form, $form_state); } /** * Get all available content entities in the environment. * * @return array */ public static function getContentEntities() { $content_entity_types = []; $entity_type_definitions = \Drupal::entityTypeManager()->getDefinitions(); /* @var $definition EntityTypeInterface */ foreach ($entity_type_definitions as $definition) { if ($definition instanceof ContentEntityType) { $content_entity_types[] = $definition; } } return $content_entity_types; } /** * {@inheritdoc} */ Loading @@ -299,7 +329,8 @@ class AddToAnySettingsForm extends ConfigFormBase { ->set('buttons_size', $values['addtoany_buttons_size']) ->set('custom_universal_button', $values['addtoany_custom_universal_button']) ->set('universal_button', $values['addtoany_universal_button']) ->set('universal_button_placement', $values['addtoany_universal_button_placement']); ->set('universal_button_placement', $values['addtoany_universal_button_placement']) ->set('library_location', $values['addtoany_library_location']); foreach (self::getContentEntities() as $entity) { $entityId = $entity->id(); Loading @@ -313,19 +344,12 @@ class AddToAnySettingsForm extends ConfigFormBase { } /** * Get all available content entities in the environment. * @return array * {@inheritdoc} */ public static function getContentEntities() { $content_entity_types = []; $entity_type_definitions = \Drupal::entityTypeManager()->getDefinitions(); /* @var $definition EntityTypeInterface */ foreach ($entity_type_definitions as $definition) { if ($definition instanceof ContentEntityType) { $content_entity_types[] = $definition; } protected function getEditableConfigNames() { return [ 'addtoany.settings', ]; } return $content_entity_types; } }
src/UpdateScripts.php 0 → 100644 +169 −0 Original line number Diff line number Diff line <?php namespace Drupal\addtoany; use Drupal\Core\File\FileUrlGeneratorInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\File\FileSystemInterface; /** * Class UpdateScripts */ class UpdateScripts { /** * Path to contract files. */ const scriptsPath = 'public://js/addtoany/menu/'; /** * List of the latest scripts to download. */ const latestScripts = 'https://www.addtoany.com/ext/updater/files_list/'; /** * The file system service. * * @var \Drupal\Core\File\FileSystemInterface */ protected $fileSystem; /** * The file URL generator. * * @var \Drupal\Core\File\FileUrlGeneratorInterface */ protected $fileUrlGenerator; /** * Logger channel. * * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface */ protected $logger; /** * The state service. * * @var \Drupal\Core\State\StateInterface */ protected $state; /** * Constructs a UpdateScripts object * * @param \Drupal\Core\File\FileSystemInterface $fileSystem * @param \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger * @param \Drupal\Core\State\StateInterface $state * */ public function __construct(FileSystemInterface $fileSystem, FileUrlGeneratorInterface $fileUrlGenerator, LoggerChannelFactoryInterface $logger, StateInterface $state) { $this->fileSystem = $fileSystem; $this->logger = $logger->get('addtoany'); $this->fileUrlGenerator = $fileUrlGenerator; $this->state = $state; } /** * Download the latest scripts. * * @see https://www.addtoany.com/ext/updater/files_list * @return false|void */ public function updateLatestScripts() { try { // List of files that will be downloaded with version. $files_to_download = $this->getScripts(); // Create directory for output $directory = self::scriptsPath . $files_to_download['version']; // Now we only need the files that will be downloaded. $latest_version = $files_to_download['version']; unset($files_to_download['version']); // Empty the directory before putting new content. //$this->fileSystem->deleteRecursive($directory); if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) { throw new \RuntimeException("Failed to create the directory: " . $directory); } foreach ($files_to_download as $file_to_download) { $content = file_get_contents($file_to_download); $name = basename($file_to_download); $file = $directory . '/' . $name; // Remove hardcoded external link in page.js that downloads information document.. if ($name == 'page.js') { preg_match('#https?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s])(.html)[-A-Za-z0-9+&@\#/%?=~_|!:,.;]+[-A-Za-z0-9+&@\#/%=~_|])#', $content, $match); $content = str_replace($match[0], '', $content); } file_put_contents($file, $content); } $this->state->set('addtoany.scripts_version', $latest_version); } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to update addtoany scripts\n", ); return FALSE; } } /** * Get a list of the latest script files * and use the hash in the file names for versioning. * * @return array|false */ public function getScripts() { try { $files_to_download = file_get_contents(self::latestScripts); $files_to_download = explode("\r\n", $files_to_download, 20); // Take the first file and extract // the hash in the name and use it for versioning. $first_file = reset($files_to_download); $file_name_parts = explode('.', basename($first_file)); $version_hash = $file_name_parts[1]; if (empty($version_hash)) { throw new \RuntimeException("Failed to get the hash from js file name: " . basename($first_file)); } $files_to_download['version'] = $version_hash; return $files_to_download; } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to get the scripts\n", ); return FALSE; } } /** * Remove all the versions of the scripts * except the latest version. * * @return void * @see getScripts() to check how versioning is done. */ public function cleanup() { try { $all_script_versions = $this->fileSystem->scanDirectory(self::scriptsPath, '/.*/', ['recurse' => FALSE]); $latest_version = $this->state->get('addtoany.scripts_version'); if (isset($all_script_versions)) { foreach ($all_script_versions as $script_version) { if ($script_version->name === $latest_version) { continue; } $this->fileSystem->deleteRecursive($script_version->uri); } } } catch (\Exception $e) { $this->logger->error( $e->getMessage() . "\n Failed to cleanup old scripts\n", ); } } }