From 111c71390fac80cfeb5c7e7c0acb870fe4600958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Mon, 24 Feb 2020 05:08:45 +0100 Subject: [PATCH 01/58] Issue #12944 - Remove all chosen related module and libs (#13087) --- composer.json | 5 -- composer.lock | 224 +------------------------------------------------- 2 files changed, 1 insertion(+), 228 deletions(-) diff --git a/composer.json b/composer.json index 7fd121bd7e6..03018a65dba 100644 --- a/composer.json +++ b/composer.json @@ -176,7 +176,6 @@ "drupal/block_visibility_groups": "^1.3", "drupal/bootstrap": "^3.17", "drupal/cancel_button": "^1.1", - "drupal/chosen": "^2.9", "drupal/ckeditor_bidi": "^2.1", "drupal/colorbutton": "1.1", "drupal/colordialog": "^1.2", @@ -247,7 +246,6 @@ "j7mbo/twitter-api-php": "^1.0", "mreq/slick-lightbox": "master", "npm-asset/blazy": "^1.8", - "npm-asset/chosen-js": "^1.8", "npm-asset/select2": "^4.0", "npm-asset/slick-carousel": "^1.8", "oomphinc/composer-installers-extender": "^1.1", @@ -334,9 +332,6 @@ "npm-asset" ], "installer-paths": { - "web/libraries/chosen": [ - "npm-asset/chosen-js" - ], "web/libraries/select2": [ "npm-asset/select2" ], diff --git a/composer.lock b/composer.lock index ef91014e576..373838bdfd2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e120bef5cbc7f13699a0db7a8622a248", + "content-hash": "2d1efe39108069c613ea1d1c9cceb624", "packages": [ { "name": "academicpuma/citeproc-php", @@ -3421,167 +3421,6 @@ "source": "https://git.drupalcode.org/project/cancel_button" } }, - { - "name": "drupal/chosen", - "version": "2.9.0", - "source": { - "type": "git", - "url": "https://git.drupalcode.org/project/chosen.git", - "reference": "8.x-2.9" - }, - "dist": { - "type": "zip", - "url": "https://ftp.drupal.org/files/projects/chosen-8.x-2.9.zip", - "reference": "8.x-2.9", - "shasum": "28f3ce08a96bb9fd0190ad9579b3b4a9d9be79c9" - }, - "require": { - "drupal/chosen_lib": "*", - "drupal/core": "^8 || ^9", - "harvesthq/chosen": "^1.8.7" - }, - "type": "drupal-module", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - }, - "drupal": { - "version": "8.x-2.9", - "datestamp": "1576963005", - "security-coverage": { - "status": "covered", - "message": "Covered by Drupal's security advisory policy" - } - } - }, - "notification-url": "https://packages.drupal.org/8/downloads", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "Cyclodex", - "homepage": "https://www.drupal.org/user/1305230" - }, - { - "name": "Dave Reid", - "homepage": "https://www.drupal.org/user/53892" - }, - { - "name": "Hydra", - "homepage": "https://www.drupal.org/user/647364" - }, - { - "name": "Pol", - "homepage": "https://www.drupal.org/user/47194" - }, - { - "name": "aidanlis", - "homepage": "https://www.drupal.org/user/502018" - }, - { - "name": "arshadcn", - "homepage": "https://www.drupal.org/user/571032" - }, - { - "name": "kalman.hosszu", - "homepage": "https://www.drupal.org/user/267481" - }, - { - "name": "nagy.balint", - "homepage": "https://www.drupal.org/user/1763952" - }, - { - "name": "supercabbageuk", - "homepage": "https://www.drupal.org/user/235438" - } - ], - "description": "Makes select elements more friendly using the Chosen jQuery plugin", - "homepage": "https://www.drupal.org/project/chosen", - "keywords": [ - "Chosen", - "Drupal" - ], - "support": { - "source": "https://drupal.org/project/chosen", - "issues": "https://drupal.org/project/issues/chosen" - } - }, - { - "name": "drupal/chosen_lib", - "version": "2.9.0", - "require": { - "drupal/chosen": "self.version", - "drupal/core": "^8 || ^9", - "php": ">=5.6.0" - }, - "type": "metapackage", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - }, - "drupal": { - "version": "8.x-2.9", - "datestamp": "1576963005", - "security-coverage": { - "status": "covered", - "message": "Covered by Drupal's security advisory policy" - } - }, - "drush": { - "services": { - "drush.services.yml": "^9" - } - } - }, - "notification-url": "https://packages.drupal.org/8/downloads", - "license": [ - "GPL-2.0-or-later" - ], - "authors": [ - { - "name": "Cyclodex", - "homepage": "https://www.drupal.org/user/1305230" - }, - { - "name": "Dave Reid", - "homepage": "https://www.drupal.org/user/53892" - }, - { - "name": "Hydra", - "homepage": "https://www.drupal.org/user/647364" - }, - { - "name": "Pol", - "homepage": "https://www.drupal.org/user/47194" - }, - { - "name": "aidanlis", - "homepage": "https://www.drupal.org/user/502018" - }, - { - "name": "arshadcn", - "homepage": "https://www.drupal.org/user/571032" - }, - { - "name": "kalman.hosszu", - "homepage": "https://www.drupal.org/user/267481" - }, - { - "name": "nagy.balint", - "homepage": "https://www.drupal.org/user/1763952" - }, - { - "name": "supercabbageuk", - "homepage": "https://www.drupal.org/user/235438" - } - ], - "description": "This module provides the basic integration with the Chosen jQuery plugin.", - "homepage": "https://www.drupal.org/project/chosen", - "support": { - "source": "https://git.drupalcode.org/project/chosen" - } - }, { "name": "drupal/ckeditor_bidi", "version": "2.1.0", @@ -9746,55 +9585,6 @@ "abandoned": true, "time": "2014-10-12T19:18:40+00:00" }, - { - "name": "harvesthq/chosen", - "version": "v1.8.7", - "source": { - "type": "git", - "url": "https://github.com/harvesthq/chosen-package.git", - "reference": "ad86732b668627c131e61ee8f0e6e9ed52e4db8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/harvesthq/chosen-package/zipball/ad86732b668627c131e61ee8f0e6e9ed52e4db8d", - "reference": "ad86732b668627c131e61ee8f0e6e9ed52e4db8d", - "shasum": "" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Koen Punt", - "homepage": "https://github.com/koenpunt" - }, - { - "name": "Patrick Filler", - "homepage": "https://github.com/pfiller" - }, - { - "name": "Christophe Coevoet", - "homepage": "https://github.com/stof" - }, - { - "name": "Ken Earley", - "homepage": "https://github.com/kenearley" - } - ], - "description": "Chosen is a JavaScript plugin that makes select boxes user-friendly. It is currently available in both jQuery and Prototype flavors.", - "homepage": "https://harvesthq.github.io/chosen/", - "keywords": [ - "dropdown", - "form", - "input", - "multiselect", - "select", - "ui" - ], - "time": "2018-06-28T20:32:51+00:00" - }, { "name": "instaclick/php-webdriver", "version": "1.4.6", @@ -10771,18 +10561,6 @@ "MIT" ] }, - { - "name": "npm-asset/chosen-js", - "version": "1.8.7", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/chosen-js/-/chosen-js-1.8.7.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, { "name": "npm-asset/select2", "version": "4.0.12", From f544de6b7a132ca4fd966aeec73f3fab85e23f4f Mon Sep 17 00:00:00 2001 From: Ashish Prabhakar Date: Tue, 25 Feb 2020 09:22:07 +0530 Subject: [PATCH 02/58] Issue #12929 - Vsite Preset - Project - Minimal (#13074) * Issue #12929 - Minimal Project Preset * Issue #12929 - Tests --- config/sync/vsite_preset.type.os_project.yml | 15 ++++++ .../menu_link_content/menulinks.csv | 2 + .../ExistingSite/VsitePresetHelperTest.php | 51 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 config/sync/vsite_preset.type.os_project.yml create mode 100644 profile/modules/vsite/modules/vsite_preset/presets/project/os_project/menu_link_content/menu_link_content/menulinks.csv diff --git a/config/sync/vsite_preset.type.os_project.yml b/config/sync/vsite_preset.type.os_project.yml new file mode 100644 index 00000000000..131c2bfae4c --- /dev/null +++ b/config/sync/vsite_preset.type.os_project.yml @@ -0,0 +1,15 @@ +uuid: 8790f640-e997-424c-bfe9-3aabceecd8ea +langcode: en +status: true +dependencies: { } +id: os_project +label: 'Minimal Project' +description: 'Blank site with no pre-set menu links or pages.' +applicableTo: + project: project +enabledApps: + event: event + news: news + page: page + profiles: profiles +privateApps: { } diff --git a/profile/modules/vsite/modules/vsite_preset/presets/project/os_project/menu_link_content/menu_link_content/menulinks.csv b/profile/modules/vsite/modules/vsite_preset/presets/project/os_project/menu_link_content/menu_link_content/menulinks.csv new file mode 100644 index 00000000000..9249e226c4f --- /dev/null +++ b/profile/modules/vsite/modules/vsite_preset/presets/project/os_project/menu_link_content/menu_link_content/menulinks.csv @@ -0,0 +1,2 @@ +Title,Route,Weight,Parent +Home,,-10,main diff --git a/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSite/VsitePresetHelperTest.php b/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSite/VsitePresetHelperTest.php index b728e955eca..c809adeb5f7 100644 --- a/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSite/VsitePresetHelperTest.php +++ b/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSite/VsitePresetHelperTest.php @@ -248,4 +248,55 @@ public function testVsiteMinimalDepartmentPresetEnableApps() { $this->assertEquals('Home', $link->getTitle()); } + /** + * Tests Project Minimal Preset. + */ + public function testProjectMinimalPreset() { + $group = $this->createGroup(); + $this->vsiteContextManager->activateVsite($group); + + $toEnable = [ + 'event' => 'event', + 'news' => 'news', + 'page' => 'page', + 'profiles' => 'profiles', + ]; + + $preset = GroupPreset::load('os_project'); + $paths = $preset->getCreationFilePaths(); + $uriArr = array_keys($paths['project']); + + // Test negative no menu links exists. + $storage = $this->entityTypeManager->getStorage('menu_link_content'); + $gid = $group->id(); + $linksArr = $storage->loadByProperties(['menu_name' => "menu-primary-$gid"]); + $this->assertEmpty($linksArr); + + $this->vsitePresetHelper->enableApps($group, $toEnable, []); + foreach ($uriArr as $uri) { + $this->vsitePresetHelper->createDefaultContent($group, $uri); + } + + // Test positive case as helper enables apps. + /** @var \Drupal\Core\Config\ImmutableConfig $app_access_config */ + $app_access_config = $this->configFactory->get('os_app_access.access'); + $this->assertNotEmpty($app_access_config); + // Check enabled. + $this->assertEquals($app_access_config->get('event'), '0'); + $this->assertEquals($app_access_config->get('news'), '0'); + $this->assertEquals($app_access_config->get('page'), '0'); + $this->assertEquals($app_access_config->get('profiles'), '0'); + // Check disabled. + $this->assertEquals($app_access_config->get('faq'), '2'); + $this->assertEquals($app_access_config->get('blog'), '2'); + + // Tests positive menu link is created too for the preset. + $linksArr = $storage->loadByProperties(['menu_name' => "menu-primary-$gid"]); + // Count should be one for Home link. + $this->assertCount(1, $linksArr); + /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $link */ + $link = array_values($linksArr)[0]; + $this->assertEquals('Home', $link->getTitle()); + } + } From 6126829fb61e7bcfb881bff12bd9dc871df585d9 Mon Sep 17 00:00:00 2001 From: Ashish Prabhakar Date: Tue, 25 Feb 2020 09:24:59 +0530 Subject: [PATCH 03/58] Issue #12931 - Users can create department/project vsites (#13090) --- config/sync/user.role.authenticated.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/sync/user.role.authenticated.yml b/config/sync/user.role.authenticated.yml index c7ad140bd56..12578f1066d 100644 --- a/config/sync/user.role.authenticated.yml +++ b/config/sync/user.role.authenticated.yml @@ -13,7 +13,9 @@ permissions: - 'access contextual links' - 'access printer-friendly version' - 'access toolbar' + - 'create department group' - 'create personal group' + - 'create project group' - 'delete bibcite_reference artwork revisions' - 'delete bibcite_reference audiovisual revisions' - 'delete bibcite_reference bill revisions' From 672d53982bbbed6cf204ab1a2d544b8a916ce107 Mon Sep 17 00:00:00 2001 From: kiran-axl <52481544+kiran-axl@users.noreply.github.com> Date: Tue, 25 Feb 2020 13:41:50 +0530 Subject: [PATCH 04/58] Issue #12674 - Section Outline Settings (#13057) * Issue #12674 - Section navigation block type created. * Issue #12674 - Removed body field from block. * Issue #12674 - Section outline form and hiding book traversal links. * Issue #12674 - Tests added. * Issue #12674 - Section outline form AJAx changes. * Issue #12674 - Section outline form changes. * Issue #12674 - Section outline - moving to other books code changes. * Issue #12674 - Section outline form ajax tests and PR comments. * Issue #12674 - Updated changes for other-book-form. * Issue #12674 - PR feedback addressed. --- .../block_content.type.section_navigation.yml | 8 + ...ock_content.section_navigation.default.yml | 34 ++ ...ock_content.section_navigation.default.yml | 14 + ...tings.block_content.section_navigation.yml | 11 + profile/modules/apps/os_pages/os_pages.module | 10 + .../apps/os_pages/os_pages.routing.yml | 16 + .../apps/os_pages/os_pages.services.yml | 2 +- .../modules/apps/os_pages/src/BooksHelper.php | 78 +++- .../os_pages/src/BooksHelperInterface.php | 24 ++ .../os_pages/src/Form/AddOtherBooksForm.php | 57 +-- .../os_pages/src/Form/SectionOutlineForm.php | 379 ++++++++++++++++++ .../src/ExistingSite/BooksHelperTest.php | 52 +++ .../src/ExistingSiteJavascript/PagesTest.php | 20 + .../SectionOutlineFormTest.php | 75 ++++ 14 files changed, 735 insertions(+), 45 deletions(-) create mode 100644 config/sync/block_content.type.section_navigation.yml create mode 100644 config/sync/core.entity_form_display.block_content.section_navigation.default.yml create mode 100644 config/sync/core.entity_view_display.block_content.section_navigation.default.yml create mode 100644 config/sync/language.content_settings.block_content.section_navigation.yml create mode 100644 profile/modules/apps/os_pages/src/Form/SectionOutlineForm.php create mode 100644 profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/SectionOutlineFormTest.php diff --git a/config/sync/block_content.type.section_navigation.yml b/config/sync/block_content.type.section_navigation.yml new file mode 100644 index 00000000000..a7ba6766470 --- /dev/null +++ b/config/sync/block_content.type.section_navigation.yml @@ -0,0 +1,8 @@ +uuid: 2de18941-af45-4c7b-9145-c7f7c663bcf9 +langcode: en +status: true +dependencies: { } +id: section_navigation +label: 'Section navigation' +revision: 1 +description: 'This widget is used in books.' diff --git a/config/sync/core.entity_form_display.block_content.section_navigation.default.yml b/config/sync/core.entity_form_display.block_content.section_navigation.default.yml new file mode 100644 index 00000000000..20309e5dabc --- /dev/null +++ b/config/sync/core.entity_form_display.block_content.section_navigation.default.yml @@ -0,0 +1,34 @@ +uuid: 95e56202-ce89-41de-ae0f-b4eaae9bd997 +langcode: en +status: true +dependencies: + config: + - block_content.type.section_navigation + module: + - field_layout + - layout_discovery +third_party_settings: + field_layout: + id: layout_onecol + settings: { } +id: block_content.section_navigation.default +targetEntityType: block_content +bundle: section_navigation +mode: default +content: + info: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + langcode: + type: language_select + weight: 2 + region: content + settings: + include_locked: true + third_party_settings: { } +hidden: { } diff --git a/config/sync/core.entity_view_display.block_content.section_navigation.default.yml b/config/sync/core.entity_view_display.block_content.section_navigation.default.yml new file mode 100644 index 00000000000..bc04496d662 --- /dev/null +++ b/config/sync/core.entity_view_display.block_content.section_navigation.default.yml @@ -0,0 +1,14 @@ +uuid: 8db7f369-d334-4965-9a4b-820a49c875a3 +langcode: en +status: true +dependencies: + config: + - block_content.type.section_navigation +id: block_content.section_navigation.default +targetEntityType: block_content +bundle: section_navigation +mode: default +content: { } +hidden: + langcode: true + search_api_excerpt: true diff --git a/config/sync/language.content_settings.block_content.section_navigation.yml b/config/sync/language.content_settings.block_content.section_navigation.yml new file mode 100644 index 00000000000..251a41250f9 --- /dev/null +++ b/config/sync/language.content_settings.block_content.section_navigation.yml @@ -0,0 +1,11 @@ +uuid: 62a9bb43-0383-436c-8a3e-c492c467b837 +langcode: en +status: true +dependencies: + config: + - block_content.type.section_navigation +id: block_content.section_navigation +target_entity_type_id: block_content +target_bundle: section_navigation +default_langcode: site_default +language_alterable: false diff --git a/profile/modules/apps/os_pages/os_pages.module b/profile/modules/apps/os_pages/os_pages.module index 0cc19858ad9..aabeda829ff 100644 --- a/profile/modules/apps/os_pages/os_pages.module +++ b/profile/modules/apps/os_pages/os_pages.module @@ -599,3 +599,13 @@ function os_pages_meta_tags_alter(array &$form, FormStateInterface $form_state) unset($form['field_meta_tags']['widget']['0']['tokens']); unset($form['field_meta_tags']['widget']['0']['basic']['#type']); } + +/** + * Implements hook_preprocess_HOOK(). + * + * Hiding book traversal links block. + */ +function os_pages_preprocess_book_navigation(&$variables) { + unset($variables['tree']); + $variables['has_links'] = FALSE; +} diff --git a/profile/modules/apps/os_pages/os_pages.routing.yml b/profile/modules/apps/os_pages/os_pages.routing.yml index 34031cd02bd..5a419f711bf 100644 --- a/profile/modules/apps/os_pages/os_pages.routing.yml +++ b/profile/modules/apps/os_pages/os_pages.routing.yml @@ -48,3 +48,19 @@ os_pages.autocomplete.books: requirements: _permission: 'access content' _group_permission: 'administer book outlines' + +os_pages.section_outline: + path: '/node/{node}/section-outline' + defaults: + _form: '\Drupal\os_pages\Form\SectionOutlineForm' + _title: 'Section Outline' + options: + _node_operation_route: TRUE + parameters: + node: + type: entity:node + requirements: + _permission: 'access content' + _group_permission: 'administer book outlines' + _entity_access: 'node.view' + node: \d+ diff --git a/profile/modules/apps/os_pages/os_pages.services.yml b/profile/modules/apps/os_pages/os_pages.services.yml index 7772a93104e..267d9ac1552 100644 --- a/profile/modules/apps/os_pages/os_pages.services.yml +++ b/profile/modules/apps/os_pages/os_pages.services.yml @@ -10,4 +10,4 @@ services: - { name: event_subscriber } os_pages.books_helper: class: Drupal\os_pages\BooksHelper - arguments: ['@entity_type.manager', '@os_pages.visibility_helper'] + arguments: ['@entity_type.manager', '@os_pages.visibility_helper', '@book.manager'] diff --git a/profile/modules/apps/os_pages/src/BooksHelper.php b/profile/modules/apps/os_pages/src/BooksHelper.php index 1e02b6eaf0c..d5893ec9f97 100644 --- a/profile/modules/apps/os_pages/src/BooksHelper.php +++ b/profile/modules/apps/os_pages/src/BooksHelper.php @@ -2,6 +2,7 @@ namespace Drupal\os_pages; +use Drupal\book\BookManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\Element\EntityAutocomplete; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -25,6 +26,13 @@ final class BooksHelper implements BooksHelperInterface { */ protected $visibilityHelper; + /** + * BookManager service. + * + * @var \Drupal\book\BookManagerInterface + */ + protected $bookManager; + /** * BooksHelper constructor. * @@ -32,10 +40,13 @@ final class BooksHelper implements BooksHelperInterface { * The entity type manager. * @param \Drupal\os_pages\VisibilityHelperInterface $visibility_helper * The visibility helper service. + * @param \Drupal\book\BookManagerInterface $book_manager + * The BookManager service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, VisibilityHelperInterface $visibility_helper) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, VisibilityHelperInterface $visibility_helper, BookManagerInterface $book_manager) { $this->nodeStorage = $entity_type_manager->getStorage('node'); $this->visibilityHelper = $visibility_helper; + $this->bookManager = $book_manager; } /** @@ -44,7 +55,8 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Vis public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.manager'), - $container->get('os_pages.visibility_helper') + $container->get('os_pages.visibility_helper'), + $container->get('book.manager') ); } @@ -87,4 +99,66 @@ public function getGroupBookResults($vsite, $matching_nids, $current_node): arra return $results; } + /** + * {@inheritdoc} + */ + public function getVsiteBooks($vsite, $current_node): array { + $results = ['' => 'Select new section']; + foreach ($vsite->getContent('group_node:page') as $group_content) { + $id = $group_content->entity_id->target_id; + $node = $this->nodeStorage->load($id); + if ($this->visibilityHelper->isBookPage($node) && $node->book['bid'] == $id && $node->book['bid'] !== $current_node->book['bid']) { + $results[$id] = $node->label(); + } + } + + return $results; + } + + /** + * {@inheritdoc} + */ + public function saveOtherBookPages($selected_book, $book_entity) { + $book_entity_id = $selected_book->id(); + $book_data = $this->bookManager->bookTreeGetFlat($book_entity->book); + $last_child_weight = (int) end($book_data)['weight']; + $link = $this->bookManager->loadBookLink($book_entity_id, FALSE); + $link['bid'] = $book_entity->book['bid']; + $link['pid'] = $book_entity->book['bid']; + $link['weight'] = $last_child_weight + 1; + $link['has_children'] = $selected_book->book['has_children']; + $this->bookManager->saveBookLink($link, FALSE); + if ($selected_book->book['has_children'] > 0) { + $this->setBidForChildren($selected_book->book, $book_entity->book['bid']); + } + } + + /** + * Looping through children elements to save all of them. + * + * @param array $book_link + * Parent node entity's book array. + * @param int $bid + * Book Id pages should be added to. + */ + protected function setBidForChildren(array $book_link, $bid) { + $flat = $this->bookManager->bookTreeGetFlat($book_link); + // Walk through the array until we find the current page. + do { + $link = array_shift($flat); + } while ($link && ($link['nid'] != $book_link['nid'])); + // Continue though the array and collect links whose parent is this page. + while (($link = array_shift($flat)) && $link['pid'] == $book_link['nid']) { + $child = $this->nodeStorage->load($link['nid']); + if ($child->book['has_children'] > 0) { + $this->setBidForChildren($child->book, $bid); + } + $link = $this->bookManager->loadBookLink($link['nid'], FALSE); + $link['bid'] = $bid; + $link['pid'] = $book_link['nid']; + $this->bookManager->saveBookLink($link, FALSE); + } + + } + } diff --git a/profile/modules/apps/os_pages/src/BooksHelperInterface.php b/profile/modules/apps/os_pages/src/BooksHelperInterface.php index 873bee5efed..11e700f60f4 100644 --- a/profile/modules/apps/os_pages/src/BooksHelperInterface.php +++ b/profile/modules/apps/os_pages/src/BooksHelperInterface.php @@ -3,6 +3,7 @@ namespace Drupal\os_pages; use Drupal\Group\Entity\GroupInterface; +use Drupal\node\NodeInterface; /** * Helper service for block visibility group. @@ -35,4 +36,27 @@ public function getMatchingNodes($input) : array; */ public function getGroupBookResults(GroupInterface $vsite, array $matching_nids, NodeInterface $node) : array; + /** + * Get all books except current book. + * + * @param \Drupal\Group\Entity\GroupInterface $vsite + * The current vsite. + * @param \Drupal\node\NodeInterface $node + * Current node entity. + * + * @return array + * Returns vsite books. + */ + public function getVsiteBooks(GroupInterface $vsite, NodeInterface $node): array; + + /** + * Save selected book page into book. + * + * @param \Drupal\node\NodeInterface $selected_book + * Selected book page node entity. + * @param \Drupal\node\NodeInterface $book_entity + * Book entity - pages should be added to. + */ + public function saveOtherBookPages(NodeInterface $selected_book, NodeInterface $book_entity); + } diff --git a/profile/modules/apps/os_pages/src/Form/AddOtherBooksForm.php b/profile/modules/apps/os_pages/src/Form/AddOtherBooksForm.php index bfb1a12b2ed..cdc76194ea1 100644 --- a/profile/modules/apps/os_pages/src/Form/AddOtherBooksForm.php +++ b/profile/modules/apps/os_pages/src/Form/AddOtherBooksForm.php @@ -7,6 +7,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\node\NodeInterface; +use Drupal\os_pages\BooksHelperInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\vsite\Plugin\VsiteContextManager; use Drupal\Core\Entity\Element\EntityAutocomplete; @@ -54,6 +55,13 @@ class AddOtherBooksForm extends FormBase { */ protected $nodeStorage; + /** + * The books Helper. + * + * @var \Drupal\os_pages\BooksHelper + */ + protected $booksHelper; + /** * Constructs a BookOutlineForm object. * @@ -63,12 +71,15 @@ class AddOtherBooksForm extends FormBase { * The BookManager service. * @param \Drupal\vsite\Plugin\VsiteContextManager $vsite_manager * The vsite Manager service. + * @param \Drupal\os_pages\BooksHelperInterface $books_helper + * Books helper service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, BookManagerInterface $book_manager, VsiteContextManager $vsite_manager) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, BookManagerInterface $book_manager, VsiteContextManager $vsite_manager, BooksHelperInterface $books_helper) { $this->bookManager = $book_manager; $this->vsiteManager = $vsite_manager; $this->vsite = $this->vsiteManager->getActiveVsite(); $this->nodeStorage = $entity_type_manager->getStorage('node'); + $this->booksHelper = $books_helper; } /** @@ -78,7 +89,8 @@ public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.manager'), $container->get('book.manager'), - $container->get('vsite.context_manager') + $container->get('vsite.context_manager'), + $container->get('os_pages.books_helper') ); } @@ -123,15 +135,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $last_child_weight = (int) end($book_data)['weight']; // Saving selected node to book. if (!empty($selected_book->book['bid'])) { - $link = $this->bookManager->loadBookLink($book_entity_id, FALSE); - $link['bid'] = $this->entity->book['bid']; - $link['pid'] = $this->entity->book['bid']; - $link['weight'] = $last_child_weight + 1; - $link['has_children'] = $selected_book->book['has_children']; - $this->bookManager->saveBookLink($link, FALSE); - if ($selected_book->book['has_children'] > 0) { - $this->setBidForChildren($selected_book->book, $this->entity->book['bid']); - } + $this->booksHelper->saveOtherBookPages($selected_book, $this->entity); } else { $selected_book->book = [ @@ -153,35 +157,4 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } - /** - * Looping through children elements to save all of them. - * - * @param array $book_link - * Parent node entity's book array. - * @param int $bid - * Book Id pages should be added to. - */ - public function setBidForChildren(array $book_link, $bid) { - $flat = $this->bookManager->bookTreeGetFlat($book_link); - - if ($book_link['has_children']) { - // Walk through the array until we find the current page. - do { - $link = array_shift($flat); - } while ($link && ($link['nid'] != $book_link['nid'])); - // Continue though the array and collect links whose parent is this page. - while (($link = array_shift($flat)) && $link['pid'] == $book_link['nid']) { - $child = $this->nodeStorage->load($link['nid']); - if ($child->book['has_children'] > 0) { - $this->setBidForChildren($child->book, $bid); - } - $link = $this->bookManager->loadBookLink($link['nid'], FALSE); - $link['bid'] = $bid; - $link['pid'] = $book_link['nid']; - $this->bookManager->saveBookLink($link, FALSE); - } - } - - } - } diff --git a/profile/modules/apps/os_pages/src/Form/SectionOutlineForm.php b/profile/modules/apps/os_pages/src/Form/SectionOutlineForm.php new file mode 100644 index 00000000000..80fd16212fb --- /dev/null +++ b/profile/modules/apps/os_pages/src/Form/SectionOutlineForm.php @@ -0,0 +1,379 @@ +nodeStorage = $node_storage; + $this->bookManager = $book_manager; + $this->booksHelper = $books_helper; + $this->vsiteManager = $vsiteContextManager; + $this->renderer = $renderer; + $this->formBuilder = $form_builder; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + $entity_manager = $container->get('entity.manager'); + return new static( + $entity_manager->getStorage('node'), + $container->get('book.manager'), + $container->get('vsite.context_manager'), + $container->get('os_pages.books_helper'), + $container->get('renderer'), + $container->get('form_builder') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'section_outline'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $node = NULL) { + $form['#title'] = $node->label(); + $form['#node'] = $node; + $this->bookAdminTable($node, $form); + $form['save'] = [ + '#type' => 'submit', + '#value' => $this->t('Save book pages'), + '#button_type' => 'primary', + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + if ($form_state->getValue('tree_hash') != $form_state->getValue('tree_current_hash')) { + $form_state->setErrorByName('', $this->t('This book has been modified by another user, the changes could not be saved.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Save elements in the same order as defined in post rather than the form. + // This ensures parent is updated before its children, preventing orphans. + $user_input = $form_state->getValues(); + if (isset($user_input['table'])) { + $order = array_flip(array_keys($user_input['table'])); + $form['table'] = array_merge($order, $form['table']); + + foreach (Element::children($form['table']) as $key) { + if ($form['table'][$key]['#item']) { + $row = $form['table'][$key]; + $values = $form_state->getValue(['table', $key]); + + // Update menu item if moved. + if ($row['parent']['pid']['#default_value'] != $values['pid'] || $row['weight']['#default_value'] != $values['weight']) { + $link = $this->bookManager->loadBookLink($values['nid'], FALSE); + $link['weight'] = $values['weight']; + $link['pid'] = $values['pid']; + $this->bookManager->saveBookLink($link, FALSE); + } + + // Update the title if changed. + if ($row['title']['#default_value'] != $values['title']) { + $node = $this->nodeStorage->load($values['nid']); + $node->revision_log = $this->t('Title changed from %original to %current.', ['%original' => $node->label(), '%current' => $values['title']]); + $node->title = $values['title']; + $node->book['link_title'] = $values['title']; + $node->setNewRevision(); + $node->save(); + $this->logger('content')->notice('book: updated %title.', ['%title' => $node->label(), 'link' => $node->toLink($this->t('View'))->toString()]); + } + } + } + } + + $this->messenger()->addStatus($this->t('Updated book %title.', ['%title' => $form['#node']->label()])); + } + + /** + * Builds the table portion of the form for the section outline page. + * + * @param \Drupal\node\NodeInterface $node + * The node of the top-level page in the book. + * @param array $form + * The form that is being modified, passed by reference. + * + * @see self::buildForm() + */ + protected function bookAdminTable(NodeInterface $node, array &$form) { + $form['table'] = [ + '#type' => 'table', + '#header' => [ + $this->t('Title'), + $this->t('Hide from section navigation'), + $this->t('Move to section navigation'), + $this->t('Weight'), + $this->t('Parent'), + ], + '#empty' => $this->t('No book content available.'), + '#tabledrag' => [ + [ + 'action' => 'match', + 'relationship' => 'parent', + 'group' => 'book-pid', + 'subgroup' => 'book-pid', + 'source' => 'book-nid', + 'hidden' => TRUE, + 'limit' => BookManager::BOOK_MAX_DEPTH - 2, + ], + [ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'book-weight', + ], + ], + '#prefix' => "
", + '#suffix' => '
', + ]; + + $tree = $this->bookManager->bookSubtreeData($node->book); + // Do not include the book item itself. + $tree = array_shift($tree); + if ($tree['below']) { + $hash = Crypt::hashBase64(serialize($tree['below'])); + // Store the hash value as a hidden form element so that we can detect + // if another user changed the book hierarchy. + $form['tree_hash'] = [ + '#type' => 'hidden', + '#default_value' => $hash, + ]; + $form['tree_current_hash'] = [ + '#type' => 'value', + '#value' => $hash, + ]; + $this->bookAdminTableTree($tree['below'], $form['table'], $node); + } + } + + /** + * Helps build the main table in the section outline page form. + * + * @param array $tree + * A subtree of the book menu hierarchy. + * @param array $form + * The form that is being modified, passed by reference. + * @param \Drupal\node\NodeInterface $node + * The current node. + * + * @see self::buildForm() + */ + protected function bookAdminTableTree(array $tree, array &$form, NodeInterface $node) { + $options = $this->booksHelper->getVsiteBooks($this->vsiteManager->getActiveVsite(), $node); + // The delta must be big enough to give each node a distinct value. + $count = count($tree); + $delta = ($count < 30) ? 15 : (int) ($count / 2) + 1; + + foreach ($tree as $data) { + $nid = $data['link']['nid']; + $id = 'book-admin-' . $nid; + + $form[$id]['#item'] = $data['link']; + $form[$id]['#nid'] = $nid; + $form[$id]['#attributes']['class'][] = 'draggable'; + $form[$id]['#weight'] = $data['link']['weight']; + + if (isset($data['link']['depth']) && $data['link']['depth'] > 2) { + $indentation = [ + '#theme' => 'indentation', + '#size' => $data['link']['depth'] - 2, + ]; + } + + $form[$id]['title'] = [ + '#prefix' => !empty($indentation) ? $this->renderer->render($indentation) : '', + '#type' => 'textfield', + '#title' => $this->t('Title'), + '#default_value' => $data['link']['title'], + '#maxlength' => 255, + '#size' => 40, + '#title_display' => 'invisible', + ]; + + $form[$id]['hide'] = [ + '#type' => 'checkbox', + '#name' => "hide-checkbox-{$id}", + '#title' => $this->t('Hide from navigation'), + '#default_value' => $data['link']['hide'] ?? '', + '#title_display' => 'invisible', + ]; + + $form[$id]['move_navigation']['books_list'] = [ + '#type' => 'select', + '#title' => $this->t('Select from books list'), + '#options' => $options, + '#name' => "books-list-{$id}", + '#title_display' => 'invisible', + ]; + + $form[$id]['move_navigation']['move'] = [ + '#type' => 'button', + '#name' => "move-btn-{$id}", + '#value' => $this->t('Move'), + '#ajax' => [ + 'callback' => '::moveSectionCallback', + 'event' => 'click', + 'wrapper' => 'section-outline-wrapper', + ], + ]; + + $form[$id]['weight'] = [ + '#type' => 'weight', + '#default_value' => $data['link']['weight'], + '#delta' => max($delta, abs($data['link']['weight'])), + '#title' => $this->t('Weight for @title', ['@title' => $data['link']['title']]), + '#title_display' => 'invisible', + '#attributes' => [ + 'class' => ['book-weight'], + ], + ]; + + $form[$id]['parent']['nid'] = [ + '#parents' => ['table', $id, 'nid'], + '#type' => 'hidden', + '#value' => $nid, + '#attributes' => [ + 'class' => ['book-nid'], + ], + ]; + + $form[$id]['parent']['pid'] = [ + '#parents' => ['table', $id, 'pid'], + '#type' => 'hidden', + '#default_value' => $data['link']['pid'], + '#attributes' => [ + 'class' => ['book-pid'], + ], + ]; + + $form[$id]['parent']['bid'] = [ + '#parents' => ['table', $id, 'bid'], + '#type' => 'hidden', + '#default_value' => $data['link']['bid'], + '#attributes' => [ + 'class' => ['book-bid'], + ], + ]; + + if ($data['below']) { + $this->bookAdminTableTree($data['below'], $form, $node); + } + } + } + + /** + * Method to move book pages to selected book. + */ + public function moveSectionCallback(array &$form, FormStateInterface $form_state) { + $button = $form_state->getTriggeringElement(); + $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2)); + $values = $form_state->getUserInput(); + $key = 'books-list-' . $button['#array_parents'][1]; + $selected_book_entity = $values[$key]; + if (!empty($selected_book_entity) && !empty($element)) { + $current_page = $this->nodeStorage->load($element['#nid']); + $book_entity = $this->nodeStorage->load($selected_book_entity); + $this->booksHelper->saveOtherBookPages($current_page, $book_entity); + $response = new AjaxResponse(); + $currentURL = Url::fromRoute(''); + $response->addCommand(new RedirectCommand($currentURL->toString())); + return $response; + } + $form_state->setRebuild(); + } + +} diff --git a/profile/modules/apps/os_pages/tests/src/ExistingSite/BooksHelperTest.php b/profile/modules/apps/os_pages/tests/src/ExistingSite/BooksHelperTest.php index a0aa72b67e6..bc1de21fb2e 100644 --- a/profile/modules/apps/os_pages/tests/src/ExistingSite/BooksHelperTest.php +++ b/profile/modules/apps/os_pages/tests/src/ExistingSite/BooksHelperTest.php @@ -5,6 +5,7 @@ use Drupal\Component\Serialization\Json; use Symfony\Component\HttpFoundation\Request; use Drupal\os_pages\Controller\BooksAutocompleteController; +use Drupal\os_pages\BooksHelper; /** * Tests for BooksHelper. @@ -15,6 +16,21 @@ */ class BooksHelperTest extends TestBase { + /** + * The books Helper. + * + * @var \Drupal\os_pages\BooksHelper + */ + protected $booksHelper; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + $this->booksHelper = $this->container->get('os_pages.books_helper'); + } + /** * Tests matching pages in Autocomplete list in add-other-books form. */ @@ -132,4 +148,40 @@ public function testNoMatchingPages() { $this->assertNotIdentical($result, $target); } + /** + * Test saveOtherBookPages method. + */ + public function testSetBidChildren() { + // Creating first book. + $book1 = $this->createBookPage([ + 'title' => 'First outline book', + ]); + // Creating sub pages. + $sub_page = $this->createBookPage([ + 'title' => 'Sub page', + ], $book1->id()); + + $grand_child = $this->createBookPage([ + 'title' => 'Grand child', + ], $book1->id(), $sub_page->id()); + + // Second book. + $book2 = $this->createBookPage([ + 'title' => 'Second book', + ]); + + $this->addGroupContent($book1, $this->group); + $this->addGroupContent($book2, $this->group); + $this->addGroupContent($sub_page, $this->group); + $this->addGroupContent($grand_child, $this->group); + + $sub_page_node = $this->getNodeByTitle('Sub page'); + $book2_node = $this->getNodeByTitle('Second book'); + $this->booksHelper->saveOtherBookPages($sub_page_node, $book2_node); + // Fetching grand child node after moving to book2. + $gc = $this->getNodeByTitle('Grand child'); + $this->assertEquals($book2->id(), $gc->book['bid']); + $this->assertEquals($sub_page->id(), $gc->book['pid']); + } + } diff --git a/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesTest.php b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesTest.php index e04c5f473d2..ba89ae29214 100644 --- a/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesTest.php +++ b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesTest.php @@ -202,4 +202,24 @@ public function testNoAddChildLink() { $web_assert->linkNotExists('Add child page'); } + /** + * Checks if Book traversal links present on book pages. + */ + public function assertNoTraversalLinks() { + /** @var \Drupal\Core\Path\AliasManagerInterface $path_alias_manager */ + $path_alias_manager = $this->container->get('path.alias_manager'); + $book = $this->createBookPage([ + 'title' => 'First book', + ]); + $sub_page = $this->createBookPage(['title' => 'Sub page'], $book->id()); + // Assertions. + $web_assert = $this->assertSession(); + $this->visit($path_alias_manager->getAliasByPath("/node/{$sub_page->id()}")); + $web_assert->statusCodeEquals(200); + $web_assert->pageTextContains('Sub page'); + $web_assert->pageTextNotContains('Book Traversal links for Sub page'); + $web_assert->linkNotExists('Up'); + $web_assert->linkNotExists('First book'); + } + } diff --git a/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/SectionOutlineFormTest.php b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/SectionOutlineFormTest.php new file mode 100644 index 00000000000..b11aa700d7e --- /dev/null +++ b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/SectionOutlineFormTest.php @@ -0,0 +1,75 @@ +createUser(); + $this->addGroupAdmin($groupAdmin, $this->group); + $this->drupalLogin($groupAdmin); + $web_assert = $this->assertSession(); + /** @var \Drupal\node\NodeInterface $book */ + // Creating first book. + $book1 = $this->createBookPage([ + 'title' => 'First outline book', + ]); + // Creating sub pages. + $sub_page = $this->createBookPage([ + 'title' => 'Sub page', + ], $book1->id()); + + $grand_child = $this->createBookPage([ + 'title' => 'Grand child', + ], $book1->id(), $sub_page->id()); + + $sub_page2 = $this->createBookPage([ + 'title' => 'Another page', + ], $book1->id()); + + // Second book. + $book2 = $this->createBookPage([ + 'title' => 'Second book', + ]); + + $this->addGroupContent($book1, $this->group); + $this->addGroupContent($book2, $this->group); + $this->addGroupContent($sub_page, $this->group); + $this->addGroupContent($grand_child, $this->group); + $this->addGroupContent($sub_page2, $this->group); + + $this->visitViaVsite("node/{$book1->id()}/section-outline", $this->group); + $web_assert->statusCodeEquals(200); + + $page = $this->getCurrentPage(); + $web_assert->fieldExists("table[book-admin-{$sub_page->id()}][title]"); + $books_field = $page->findField("books-list-book-admin-{$sub_page->id()}"); + $books_field->setValue($book2->id()); + $web_assert->buttonExists("move-btn-book-admin-{$sub_page->id()}")->click(); + $web_assert->assertNoElementAfterWait('css', '.ajax-progress-throbber'); + // Asserting page status is 200 after reload. + $web_assert->statusCodeEquals(200); + $web_assert->fieldNotExists("table[book-admin-{$sub_page->id()}][title]"); + $web_assert->fieldNotExists("table[book-admin-{$grand_child->id()}][title]"); + $web_assert->fieldExists("table[book-admin-{$sub_page2->id()}][title]"); + $this->visitViaVsite("node/{$sub_page->id()}", $this->group); + $web_assert->statusCodeEquals(200); + // Fetching grand child node after moving to book2. + $gc = $this->getNodeByTitle('Grand child'); + $this->assertEquals($book2->id(), $gc->book['bid']); + // Fetching sub page node after moving to book2. + $sp = $this->getNodeByTitle('Sub page'); + $this->assertEquals($book2->id(), $sp->book['bid']); + $this->assertEquals($sp->id(), $gc->book['pid']); + } + +} From bff6a5526bebf907cd6ddd366c9e1402b3132bb2 Mon Sep 17 00:00:00 2001 From: kiran-axl <52481544+kiran-axl@users.noreply.github.com> Date: Tue, 25 Feb 2020 15:17:31 +0530 Subject: [PATCH 05/58] Issue #13093 - Only show books related to current vsite (#13094) * Issue #13093 - Issue #12674 - Fixed vsite books options during node edit. * Issue #13093 - Issue #12674 - Hotfix to show book checkbox for non-book pages. * Issue #13093 - Tests for bug related changes added. --- profile/modules/apps/os_pages/os_pages.module | 39 +++++++++---- .../ExistingSiteJavascript/PagesFormTest.php | 56 +++++++++++++++++++ 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/profile/modules/apps/os_pages/os_pages.module b/profile/modules/apps/os_pages/os_pages.module index aabeda829ff..962afd574fe 100644 --- a/profile/modules/apps/os_pages/os_pages.module +++ b/profile/modules/apps/os_pages/os_pages.module @@ -322,7 +322,7 @@ function os_pages_node_page_alter(array &$form, FormStateInterface $form_state) // Here, set NID value to new if a new book is to be created. $nid = !$node->isNew() ? $node->id() : 'new'; - if ($nid === 'new' && $active_vsite->hasPermission('create new books', $current_user)) { + if ($active_vsite->hasPermission('create new books', $current_user) && ($nid === 'new' || $node->book['bid'] == 0)) { $form['book']['bid']['#access'] = FALSE; $form['book']['pid']['#access'] = FALSE; unset($form['book']['weight']); @@ -346,6 +346,10 @@ function os_pages_node_page_alter(array &$form, FormStateInterface $form_state) ]; } + // Setting filtered vsite books in node edit book-outline section. + $book_options = _os_pages_book_outline_form_options($form['book']['bid']['#options']); + $form['book']['bid']['#options'] = $book_options; + // Setting bid as parent or 'new' if its a new book. if (isset($parent)) { $parent_node = Node::load($parent); @@ -556,6 +560,29 @@ function os_pages_node_links_alter(array &$links, NodeInterface $node, array &$c * Implements hook_form_BASE_FORM_ID_alter(). */ function os_pages_form_node_page_book_outline_form_alter(&$form, FormStateInterface $form_state, $form_id) { + $current_nid = $form['book']['nid']['#value']; + $book_options = _os_pages_book_outline_form_options($form['book']['bid']['#options']); + + // Setting filtered books from this vsite. + $form['book']['bid']['#options'] = $book_options; + $link = Link::fromTextAndUrl(t('Add other book pages to this outline'), Url::fromRoute('os_pages.add_other_books', ['node' => $current_nid])); + $link = new FormattableMarkup($link->toString(), []); + $form['book']['add_book_pages'] = [ + '#markup' => $link, + '#weight' => -10, + ]; +} + +/** + * Method to filter books within vsite. + * + * @param array $book_options + * An array of all books. + * + * @return array + * Returns the filtered books. + */ +function _os_pages_book_outline_form_options(array $book_options) { /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ $vsite_context_manager = \Drupal::service('vsite.context_manager'); /** @var \Drupal\group\Entity\GroupInterface|null $active_vsite */ @@ -565,22 +592,14 @@ function os_pages_form_node_page_book_outline_form_alter(&$form, FormStateInterf $vsite_nids[] = $group_content->entity_id->target_id; } - $current_nid = $form['book']['nid']['#value']; - $book_options = $form['book']['bid']['#options']; // Removing form options if page is not from this vsite. foreach ($book_options as $key => $value) { if (!in_array($key, $vsite_nids)) { unset($book_options[$key]); } } - $form['book']['bid']['#options'] = $book_options; - $link = Link::fromTextAndUrl(t('Add other book pages to this outline'), Url::fromRoute('os_pages.add_other_books', ['node' => $current_nid])); - $link = new FormattableMarkup($link->toString(), []); - $form['book']['add_book_pages'] = [ - '#markup' => $link, - '#weight' => -10, - ]; } + return $book_options; } /** diff --git a/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesFormTest.php b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesFormTest.php index 2c017536c3e..8545959b041 100644 --- a/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesFormTest.php +++ b/profile/modules/apps/os_pages/tests/src/ExistingSiteJavascript/PagesFormTest.php @@ -132,4 +132,60 @@ public function testAddOtherBooksForm() { $this->assertSession()->responseNotContains($title); } + /** + * Test only vsite books present in Book Outline form. + */ + public function testNodeVsiteBooksList() { + $this->groupAdmin = $this->createUser(); + $this->addGroupAdmin($this->groupAdmin, $this->group); + $this->drupalLogin($this->groupAdmin); + /** @var \Drupal\node\NodeInterface $book */ + $book = $this->createBookPage([ + 'title' => 'First outline book', + ]); + $book2 = $this->createBookPage([ + 'title' => 'Second outline book', + ]); + + $this->addGroupContent($book, $this->group); + $this->addGroupContent($book2, $this->group); + + // Creating another book page in another vSite. + $book3 = $this->createBookPage([ + 'title' => 'Another vsite book', + ]); + $vsite2 = $this->createGroup(); + $this->addGroupContent($book3, $vsite2); + + $this->visitViaVsite("node/{$book->id()}/edit", $this->group); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->selectExists('edit-book-bid'); + $this->assertSession()->optionExists('edit-book-bid', 'Second outline book'); + $this->assertSession()->optionNotExists('edit-book-bid', 'Another vsite book'); + + // Checking other vsite book outline. + $this->addGroupAdmin($this->groupAdmin, $vsite2); + $this->visitViaVsite("node/{$book3->id()}/edit", $vsite2); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->selectExists('edit-book-bid'); + $this->assertSession()->optionExists('edit-book-bid', 'Another vsite book'); + } + + /** + * Test to check Book checkbox on pages edit. + */ + public function testOutlineOnPages() { + $this->groupAdmin = $this->createUser(); + $this->addGroupAdmin($this->groupAdmin, $this->group); + $this->drupalLogin($this->groupAdmin); + $page = $this->createNode([ + 'type' => 'page', + 'title' => 'Standalone page', + ]); + $this->addGroupContent($page, $this->group); + $this->visitViaVsite("node/{$page->id()}/edit", $this->group); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->checkboxNotChecked('edit-book-checkbox'); + } + } From 1aca70c56d722d2fcbef53b13f2cde3951a4b278 Mon Sep 17 00:00:00 2001 From: Uttkarsh Tiwari <38376852+uttkarsh-26@users.noreply.github.com> Date: Tue, 25 Feb 2020 16:11:58 +0530 Subject: [PATCH 06/58] Issue #12921 - Fix - No authors in publications after import (#13089) * Issue #12921 - Update bibcite to latest dev to fix Authors not appearing issue and support for coded year import. * Issue #12921 - Test failures due to AccessHelper fix. * Issue #12921 - Test fixes. --- composer.json | 3 +- composer.lock | 52 +++++++++---------- .../os_publications/os_publications.module | 8 +++ .../src/Helper/CpImportPublicationHelper.php | 10 ++++ .../ExistingSite/CpImportPublicationsTest.php | 44 ++++++++++++++++ .../PublicationPreviewFunctionalTest.php | 4 +- profile/modules/os/src/AccessHelper.php | 2 +- 7 files changed, 91 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index 03018a65dba..d029a488eea 100644 --- a/composer.json +++ b/composer.json @@ -411,8 +411,7 @@ "Update is.gd service api url": "https://www.drupal.org/files/issues/2019-07-03/update-isgd-api-3065567-2.patch" }, "drupal/bibcite": { - "Extending the supported bibcite formats.": "patches/bibcite_formats_extension.patch", - "Editors and others roles treated as author": "https://www.drupal.org/files/issues/2019-08-01/other-roles-shown-as-authors-3006180-6.patch" + "Extending the supported bibcite formats.": "patches/bibcite_formats_extension.patch" }, "drupal/config_ignore": { "Override drush cim/cex for filtering": "https://www.drupal.org/files/issues/2019-01-08/2973431-supplementary-drush-commands-17.patch", diff --git a/composer.lock b/composer.lock index 373838bdfd2..a30cfdc5326 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2d1efe39108069c613ea1d1c9cceb624", + "content-hash": "47da57be3681f7267ca3a866d29ab984", "packages": [ { "name": "academicpuma/citeproc-php", @@ -106,16 +106,16 @@ }, { "name": "adci/full-name-parser", - "version": "0.2.3", + "version": "0.2.4", "source": { "type": "git", "url": "https://github.com/ADCI/full-name-parser.git", - "reference": "657ea52e39adce94f297970c4fbd5c70db17a3b5" + "reference": "2c59942d97195bbdc101e3d1a0ad01519577edb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ADCI/full-name-parser/zipball/657ea52e39adce94f297970c4fbd5c70db17a3b5", - "reference": "657ea52e39adce94f297970c4fbd5c70db17a3b5", + "url": "https://api.github.com/repos/ADCI/full-name-parser/zipball/2c59942d97195bbdc101e3d1a0ad01519577edb0", + "reference": "2c59942d97195bbdc101e3d1a0ad01519577edb0", "shasum": "" }, "require": { @@ -149,7 +149,7 @@ "parser", "php" ], - "time": "2019-03-25T08:56:48+00:00" + "time": "2019-11-05T05:32:16+00:00" }, { "name": "alchemy/zippy", @@ -297,9 +297,9 @@ "authors": [ { "name": "Nils Werner", - "role": "Developer", "email": "nils.werner@audiolabs-erlangen.de", - "homepage": "http://www.audiolabs-erlangen.de" + "homepage": "http://www.audiolabs-erlangen.de", + "role": "Developer" } ], "description": "Bibtex parser for PHP 5.3", @@ -3003,14 +3003,14 @@ "source": { "type": "git", "url": "https://git.drupalcode.org/project/bibcite.git", - "reference": "6dc81504199720cdc1aafad245bdcc8e66535088" + "reference": "e65c110116fcefbbd30fbf8a4adc6f5754b59a5c" }, "require": { "academicpuma/citeproc-php": "~1.0", - "adci/full-name-parser": "^0.2", + "adci/full-name-parser": "^0.2.4", "audiolabs/bibtexparser": "dev-master", "caseyamcl/php-marc21": "~1.0", - "drupal/core": "*", + "drupal/core": "^8 || ^9", "drupal/entity": "^1.0", "technosophos/libris": "~2.0" }, @@ -3018,22 +3018,28 @@ "drupal/bibcite_entity": "*", "drupal/entity": "*" }, + "suggest": { + "drupal/bibcite_altmetric": "Adds Altmetric badges to BibCite reference entities", + "drupal/bibcite_crossref": "Provides DOI lookup functionality", + "drupal/bibcite_migrate": "Migrate your bibliographic data from the Bibliography (biblio) module", + "drupal/bibcite_pubmed": "Provides PubMed import and lookup functionality", + "drupal/metatag_google_scholar": "Provides number of meta tags to help with indexing of scholarly content/articles in Google Scholar" + }, "type": "drupal-module", "extra": { "branch-alias": { "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0-alpha10+25-dev", - "datestamp": "1564740485", + "version": "8.x-1.0-alpha10+43-dev", + "datestamp": "1581075598", "security-coverage": { "status": "not-covered", "message": "Project has not opted into security advisory coverage!" } }, "patches_applied": { - "Extending the supported bibcite formats.": "patches/bibcite_formats_extension.patch", - "Editors and others roles treated as author": "https://www.drupal.org/files/issues/2019-08-01/other-roles-shown-as-authors-3006180-6.patch" + "Extending the supported bibcite formats.": "patches/bibcite_formats_extension.patch" } }, "notification-url": "https://packages.drupal.org/8/downloads", @@ -3068,7 +3074,7 @@ "source": "http://cgit.drupalcode.org/bibcite", "issues": "https://www.drupal.org/project/issues/bibcite" }, - "time": "2019-08-02T10:44:42+00:00" + "time": "2020-02-18T10:08:45+00:00" }, { "name": "drupal/bibcite_entity", @@ -5841,8 +5847,8 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0-alpha2+94-dev", - "datestamp": "1528091885", + "version": "8.x-1.0-alpha2+72-dev", + "datestamp": "1526651284", "security-coverage": { "status": "not-covered", "message": "Dev releases are not covered by Drupal security advisories." @@ -5872,10 +5878,6 @@ { "name": "tim.plunkett", "homepage": "https://www.drupal.org/user/241634" - }, - { - "name": "tstoeckler", - "homepage": "https://www.drupal.org/user/107158" } ], "description": "Integrates the Fullcalender Library from https://fullcalendar.io", @@ -16219,10 +16221,6 @@ "name": "cs_shadow", "homepage": "https://www.drupal.org/user/2828287" }, - { - "name": "oknate", - "homepage": "https://www.drupal.org/user/471638" - }, { "name": "phenaproxima", "homepage": "https://www.drupal.org/user/205645" @@ -16348,7 +16346,7 @@ }, "drupal": { "version": "8.x-1.0-rc1", - "datestamp": "1568446684", + "datestamp": "1527030784", "security-coverage": { "status": "not-covered", "message": "RC releases are not covered by Drupal security advisories." diff --git a/profile/modules/apps/os_publications/os_publications.module b/profile/modules/apps/os_publications/os_publications.module index 5dd1322f87b..8e8b06ae256 100644 --- a/profile/modules/apps/os_publications/os_publications.module +++ b/profile/modules/apps/os_publications/os_publications.module @@ -1261,11 +1261,19 @@ function os_publications_bibcite_reference_form_alter_metadata_access(array &$fo $has_administer_reference_access = $active_vsite->hasPermission('administer bibcite_reference', $current_user); /** @var bool $has_create_alias_access */ $has_create_alias_access = $active_vsite->hasPermission('create url aliases', $current_user); + /** @var bool $has_publish_content_access */ + $has_publish_content_access = $active_vsite->hasPermission('publish nodes', $current_user); + /** @var bool $has_create_access */ + $has_create_access = $active_vsite->hasPermission('create publications', $current_user); $form['created']['#access'] = $has_administer_reference_access; $form['uid']['#access'] = $has_administer_reference_access; $form['path']['widget']['0']['#access'] = $has_create_alias_access; $form['path']['#access'] = $has_create_alias_access; + $form['status']['#access'] = $has_publish_content_access; + $form['revision_information']['#access'] = $has_create_access; + $form['revision']['#access'] = $has_create_access; + } /** diff --git a/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php b/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php index ac00bdb5720..fd845978be7 100644 --- a/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php +++ b/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php @@ -91,6 +91,16 @@ public function savePublicationEntity(array $entry, $formatId): array { 'keyword_deduplication' => $config->get('settings.keyword_deduplication'), ]; + // To handle special cases when year is a coded string instead of a number. + $yearMapping = $this->configFactory->get('os_publications.settings')->get('publications_years_text'); + if (isset($entry['year']) && is_string($entry['year'])) { + foreach ($yearMapping as $code => $text) { + if (strtolower(str_replace(' ', '', $entry['year'])) === strtolower(str_replace(' ', '', $text))) { + $entry['year'] = $code; + } + } + } + /** @var \Drupal\bibcite_entity\Entity\Reference $entity */ try { $entity = $this->serializer->denormalize($entry, Reference::class, $format->getPluginId(), $denormalize_context); diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php index 57d33974466..01e5f2330cb 100644 --- a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php @@ -90,6 +90,50 @@ public function testCpImportHelperSavePublicationBibtex() { $this->assertEquals($abstract, $pubEntity->get('html_abstract')->getValue()[0]['value']); } + /** + * Tests Saving a Bibtex entry works with year as string and correct mapping. + * + * @covers ::savePublicationEntity + * @covers ::mapPublicationHtmlFields + */ + public function testCpImportHelperSavePublicationBibtexCodedYear() { + + $storage = $this->entityTypeManager->getStorage('bibcite_reference'); + $title = $this->randomString(); + + // Prepare data entry array. + $abstract = 'This paper presents measurements of spectrally'; + $entry = [ + 'type' => 'article', + 'journal' => 'Proceeding of the Combustion Institute', + 'title' => $title, + 'volume' => '32', + 'year' => 'In Press', + 'pages' => '963-970', + 'chapter' => '963', + 'abstract' => $abstract, + 'author' => ['M. Nind', 'L. Find'], + ]; + + $context = $this->cpImportHelper->savePublicationEntity($entry, 'bibtex'); + + $pubArr = $storage->loadByProperties([ + 'type' => 'journal_article', + 'title' => $title, + ]); + + // Assert Saving Bibtex entry with string year worked. + $this->assertNotEmpty($pubArr); + $this->assertArrayHasKey('success', $context); + /** @var \Drupal\bibcite_entity\Entity\Reference $pubEntity */ + $pubEntity = array_values($pubArr)[0]; + $this->markEntityForCleanup($pubEntity); + // Assert values. + $this->assertEquals($title, $pubEntity->get('title')->getValue()[0]['value']); + // Test year is mapped correctly. + $this->assertEquals(10030, $pubEntity->get('bibcite_year')->getValue()[0]['value']); + } + /** * Tests Saving a Pubmed entry works. * diff --git a/profile/modules/custom/bibcite_preview/tests/src/ExistingSiteJavascript/PublicationPreviewFunctionalTest.php b/profile/modules/custom/bibcite_preview/tests/src/ExistingSiteJavascript/PublicationPreviewFunctionalTest.php index d15790ec725..97ecfc68ea4 100644 --- a/profile/modules/custom/bibcite_preview/tests/src/ExistingSiteJavascript/PublicationPreviewFunctionalTest.php +++ b/profile/modules/custom/bibcite_preview/tests/src/ExistingSiteJavascript/PublicationPreviewFunctionalTest.php @@ -47,7 +47,7 @@ public function testPublicationEditPreviewAndBack() { $preview_button->press(); $web_assert->statusCodeEquals(200); - $back_link = $page->findById('edit-backlink'); + $back_link = $page->findLink('Back to content editing'); $back_link->press(); $web_assert->statusCodeEquals(200); @@ -72,7 +72,7 @@ public function testPublicationCreatePreviewAndBack() { $preview_button->press(); $web_assert->statusCodeEquals(200); - $back_link = $page->findById('edit-backlink'); + $back_link = $page->findLink('Back to content editing'); $back_link->press(); $web_assert->statusCodeEquals(200); diff --git a/profile/modules/os/src/AccessHelper.php b/profile/modules/os/src/AccessHelper.php index bbf2148ab73..2ece9be2fb4 100644 --- a/profile/modules/os/src/AccessHelper.php +++ b/profile/modules/os/src/AccessHelper.php @@ -82,7 +82,7 @@ public function checkAccess(EntityInterface $entity, string $operation, AccountI // Only act if there are group content types for this plugin. $group_content_types = GroupContentType::loadByContentPluginId($plugin_id); - if (empty($group_content_types)) { + if (empty($group_content_types) || $entity->id() === NULL) { return AccessResult::neutral(); } From 4a9125294f8345b956465ee63bfd6903b6b63bba Mon Sep 17 00:00:00 2001 From: Subhojit Paul Date: Tue, 25 Feb 2020 19:48:33 +0530 Subject: [PATCH 07/58] Issue #12991 - Don't clear all css/js when custom theme is updated (#13024) * Issue #12991 - advagg module and default settings * Issue #12991 - add support incase admin want to tweak the performance * Revert "Issue #12991 - add support incase admin want to tweak the performance" This reverts commit a9db01de5066d2cf83dfbad31aa6861642ec6d09. * Revert "Issue #12991 - advagg module and default settings" This reverts commit 38ee04a4d2a6d619a745adb88e9ec2df173fe03d. * Issue #12991 - enable css/js aggregation * Issue #12991 - Fix - Custom theme styles not updated for user * Issue #12991 - override the core's css renderer * Issue #12991 - decided to use service decorator Read the Symfony and Drupal doc for overriding existing services, and figured that service decorator will fit here well. We don't want to override the core's service completely, it is still available, and at the same we are providing an extended version of that service. * Issue #12991 - Alter custom theme specific query string * Issue #12991 - better documentation * Issue #12991 - handle custom theme script cache separately * Issue #12991 - tests for verifying browser cache is working as expected * Issue #12991 - Code refactoring Remove unnecessary method. * Issue #12991 - flush vsite specific css/js cache * Issue #12991 - Fix - Style not updated for anonymous user * Issue #12991 - CssCollectionRenderer test * Issue #12991 - JsCollectionRenderer test * Issue #12991 - vsiteFlushCssJs test * Issue #12991 - More assertions in functional test * Issue #12991 - add more coverage metadata * Issue #12991 - update PreviewActionOsThemePreviewTest::testSave * Issue #12991 - Probably the cleanup is not needed anymore * Revert "Issue #12991 - Probably the cleanup is not needed anymore" This reverts commit 6b8ad09ae3aeda1569823994a0b5c21a0f86d5b5. * Issue #12991 - Update AppearanceSettingsTest::testSave * Issue #12991 - update AppearanceSettingsTest::testSetDefault * Issue #12991 - update EventOsFullCalendarTest::testOsFullCalendarLibraryLoad * Issue #12991 - advagg * Issue #12991 - remove unnecessary metadata * Issue #12991 - allow instances to disable aggregation and optimizers * Revert "Issue #12991 - advagg" This reverts commit 1f3678252dae0d766932802fd72b6fe5e6cd6aea. * Issue #12991 - advagg cleanups --- .../sync/config_split.config_split.local.yml | 1 + config/sync/system.performance.yml | 4 +- .../cp_appearance/cp_appearance.module | 17 +- .../cp_appearance/cp_appearance.services.yml | 10 + .../src/CssCollectionRenderer.php | 82 ++++++++ .../cp_appearance/src/Entity/CustomTheme.php | 10 +- .../src/JsCollectionRenderer.php | 82 ++++++++ .../ExistingSite/AppearanceSettingsTest.php | 16 +- .../CustomThemeBrowserCacheTest.php | 148 ++++++++++++++ .../src/Unit/CssCollectionRendererTest.php | 177 ++++++++++++++++ .../src/Unit/JsCollectionRendererTest.php | 192 ++++++++++++++++++ .../EventOsFullCalendarTest.php | 2 +- .../PreviewActionOsThemePreviewTest.php | 6 +- .../vsite/src/Plugin/VsiteContextManager.php | 7 +- .../Plugin/VsiteContextManagerInterface.php | 11 + .../ExistingSite/VsiteContextManagerTest.php | 16 ++ 16 files changed, 766 insertions(+), 15 deletions(-) create mode 100644 profile/modules/cp/modules/cp_appearance/src/CssCollectionRenderer.php create mode 100644 profile/modules/cp/modules/cp_appearance/src/JsCollectionRenderer.php create mode 100644 profile/modules/cp/modules/cp_appearance/tests/src/ExistingSiteJavascript/CustomThemeBrowserCacheTest.php create mode 100644 profile/modules/cp/modules/cp_appearance/tests/src/Unit/CssCollectionRendererTest.php create mode 100644 profile/modules/cp/modules/cp_appearance/tests/src/Unit/JsCollectionRendererTest.php diff --git a/config/sync/config_split.config_split.local.yml b/config/sync/config_split.config_split.local.yml index a8ea636e1f6..99b57094cde 100644 --- a/config/sync/config_split.config_split.local.yml +++ b/config/sync/config_split.config_split.local.yml @@ -19,6 +19,7 @@ graylist: - os_media.settings - os_publications.settings - search_api.server.os_search + - system.performance graylist_dependents: true graylist_skip_equal: true weight: 0 diff --git a/config/sync/system.performance.yml b/config/sync/system.performance.yml index 65d6e1a3052..d4f85d555a5 100644 --- a/config/sync/system.performance.yml +++ b/config/sync/system.performance.yml @@ -2,7 +2,7 @@ cache: page: max_age: 0 css: - preprocess: false + preprocess: true gzip: true fast_404: enabled: true @@ -10,7 +10,7 @@ fast_404: exclude_paths: '/\/(?:styles|imagecache)\//' html: '404 Not Found

Not Found

The requested URL "@path" was not found on this server.

' js: - preprocess: false + preprocess: true gzip: true stale_file_threshold: 2592000 _core: diff --git a/profile/modules/cp/modules/cp_appearance/cp_appearance.module b/profile/modules/cp/modules/cp_appearance/cp_appearance.module index 8cddddfba92..24a3b099d3d 100644 --- a/profile/modules/cp/modules/cp_appearance/cp_appearance.module +++ b/profile/modules/cp/modules/cp_appearance/cp_appearance.module @@ -6,6 +6,7 @@ */ use Drupal\cp_appearance\Entity\CustomThemeInterface; +use Drupal\vsite\Plugin\VsiteContextManager; /** * Implements hook_theme(). @@ -63,10 +64,20 @@ function cp_appearance_cp_custom_theme_update(CustomThemeInterface $custom_theme $cache->invalidate("theme.active_theme.{$custom_theme->id()}"); } + /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ + $vsite_context_manager = \Drupal::service('vsite.context_manager'); + /** @var \Drupal\group\Entity\GroupInterface|null $active_vsite */ + $active_vsite = $vsite_context_manager->getActiveVsite(); + // Make sure the browser assets are flushed. Otherwise, user will see the // old styles and scripts. - if (($custom_theme->getStyles() !== $original->getStyles()) || - ($custom_theme->getScripts() !== $original->getScripts())) { - _drupal_flush_css_js(); + if ($active_vsite && + (($custom_theme->getStyles() !== $original->getStyles()) || + ($custom_theme->getScripts() !== $original->getScripts()))) { + VsiteContextManager::vsiteFlushCssJs($active_vsite); + + /** @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_invalidator */ + $cache_invalidator = \Drupal::service('cache_tags.invalidator'); + $cache_invalidator->invalidateTags(["rendered:vsite:{$active_vsite->id()}"]); } } diff --git a/profile/modules/cp/modules/cp_appearance/cp_appearance.services.yml b/profile/modules/cp/modules/cp_appearance/cp_appearance.services.yml index 0fbdfbfab3a..a0d34b181f5 100644 --- a/profile/modules/cp/modules/cp_appearance/cp_appearance.services.yml +++ b/profile/modules/cp/modules/cp_appearance/cp_appearance.services.yml @@ -18,3 +18,13 @@ services: arguments: ['@config.factory', '@theme.manager', '@theme.initialization'] tags: - {name: event_subscriber} + cp_appearance.css_collection_renderer: + class: \Drupal\cp_appearance\CssCollectionRenderer + public: false + decorates: asset.css.collection_renderer + arguments: ['@cp_appearance.css_collection_renderer.inner', '@state', '@vsite.context_manager'] + cp_appearance.js_collection_renderer: + class: \Drupal\cp_appearance\JsCollectionRenderer + public: false + decorates: asset.js.collection_renderer + arguments: ['@cp_appearance.js_collection_renderer.inner', '@state', '@vsite.context_manager'] diff --git a/profile/modules/cp/modules/cp_appearance/src/CssCollectionRenderer.php b/profile/modules/cp/modules/cp_appearance/src/CssCollectionRenderer.php new file mode 100644 index 00000000000..3d7e38be74e --- /dev/null +++ b/profile/modules/cp/modules/cp_appearance/src/CssCollectionRenderer.php @@ -0,0 +1,82 @@ +coreCssCollectionRenderer = $css_collection_renderer; + $this->state = $state; + $this->vsiteContextManager = $vsite_context_manager; + } + + /** + * {@inheritdoc} + */ + public function render(array $assets): array { + $elements = $this->coreCssCollectionRenderer->render($assets); + /** @var \Drupal\group\Entity\GroupInterface|null $active_vsite */ + $active_vsite = $this->vsiteContextManager->getActiveVsite(); + + if (!$active_vsite) { + return $elements; + } + + // Only alter the query string for any custom theme style. + array_walk($elements, function (&$item, $index) use ($assets, $active_vsite) { + if (strpos($item['#attributes']['href'], CustomTheme::CUSTOM_THEME_ID_PREFIX) !== FALSE) { + $query_string_separator = (strpos($assets[$index]['data'], '?') !== FALSE) ? '&' : '?'; + list($path) = explode($query_string_separator, $item['#attributes']['href']); + + $new_query_string = $this->state->get(VsiteContextManager::VSITE_CSS_JS_QUERY_STRING_STATE_KEY_PREFIX . $active_vsite->id(), 0); + + $item['#attributes']['href'] = "$path$query_string_separator$new_query_string"; + } + }); + + return $elements; + } + +} diff --git a/profile/modules/cp/modules/cp_appearance/src/Entity/CustomTheme.php b/profile/modules/cp/modules/cp_appearance/src/Entity/CustomTheme.php index 928094b280a..2a9349ebbda 100644 --- a/profile/modules/cp/modules/cp_appearance/src/Entity/CustomTheme.php +++ b/profile/modules/cp/modules/cp_appearance/src/Entity/CustomTheme.php @@ -1,5 +1,7 @@ -1, 'css' => [ 'theme' => [ - self::CUSTOM_THEMES_STYLE_LOCATION => [], + self::CUSTOM_THEMES_STYLE_LOCATION => [ + 'preprocess' => FALSE, + ], ], ], 'js' => [ - self::CUSTOM_THEMES_SCRIPT_LOCATION => [], + self::CUSTOM_THEMES_SCRIPT_LOCATION => [ + 'preprocess' => FALSE, + ], ], ], ]; diff --git a/profile/modules/cp/modules/cp_appearance/src/JsCollectionRenderer.php b/profile/modules/cp/modules/cp_appearance/src/JsCollectionRenderer.php new file mode 100644 index 00000000000..e4c7fcad27f --- /dev/null +++ b/profile/modules/cp/modules/cp_appearance/src/JsCollectionRenderer.php @@ -0,0 +1,82 @@ +coreJsCollectionRenderer = $js_collection_renderer; + $this->state = $state; + $this->vsiteContextManager = $vsite_context_manager; + } + + /** + * {@inheritdoc} + */ + public function render(array $assets): array { + $elements = $this->coreJsCollectionRenderer->render($assets); + /** @var \Drupal\group\Entity\GroupInterface|null $active_vsite */ + $active_vsite = $this->vsiteContextManager->getActiveVsite(); + + if (!$active_vsite) { + return $elements; + } + + // Only alter the query string for any custom theme script. + array_walk($elements, function (&$item) use ($active_vsite) { + if (isset($item['#attributes']['src']) && + strpos($item['#attributes']['src'], CustomTheme::CUSTOM_THEME_ID_PREFIX) !== FALSE) { + list($path) = explode('?', $item['#attributes']['src']); + + $new_query_string = $this->state->get(VsiteContextManager::VSITE_CSS_JS_QUERY_STRING_STATE_KEY_PREFIX . $active_vsite->id(), 0); + + $item['#attributes']['src'] = "$path?$new_query_string"; + } + }); + + return $elements; + } + +} diff --git a/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsTest.php b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsTest.php index 71451ba3767..14dd23b14c8 100644 --- a/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsTest.php +++ b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsTest.php @@ -52,8 +52,12 @@ public function testSave(): void { $this->getCurrentPage()->selectFieldOption('theme', 'hwpi_lamont'); $this->getCurrentPage()->pressButton('Save Theme'); - $this->visit('/cp-appearance'); - $this->assertSession()->responseContains('/profiles/contrib/openscholar/themes/hwpi_lamont/css/style.css'); + /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */ + $config_factory = $this->container->get('config.factory'); + /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ + $vsite_context_manager = $this->container->get('vsite.context_manager'); + $vsite_context_manager->activateVsite($this->group); + $this->assertEquals('hwpi_lamont', $config_factory->get('system.theme')->get('default')); $this->visit('/'); } @@ -68,8 +72,12 @@ public function testSetDefault(): void { $this->assertSession()->statusCodeEquals(200); - $this->visit('/cp-appearance'); - $this->assertSession()->responseContains('/profiles/contrib/openscholar/themes/hwpi_college/css/style.css'); + /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */ + $config_factory = $this->container->get('config.factory'); + /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ + $vsite_context_manager = $this->container->get('vsite.context_manager'); + $vsite_context_manager->activateVsite($this->group); + $this->assertEquals('hwpi_college', $config_factory->get('system.theme')->get('default')); $this->visit('/'); } diff --git a/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSiteJavascript/CustomThemeBrowserCacheTest.php b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSiteJavascript/CustomThemeBrowserCacheTest.php new file mode 100644 index 00000000000..4cb39923977 --- /dev/null +++ b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSiteJavascript/CustomThemeBrowserCacheTest.php @@ -0,0 +1,148 @@ +groupAdmin = $this->createUser(); + $this->addGroupAdmin($this->groupAdmin, $this->group); + $this->drupalLogin($this->groupAdmin); + } + + /** + * @covers \Drupal\cp_appearance\CssCollectionRenderer + * @covers \Drupal\cp_appearance\JsCollectionRenderer + * @covers \Drupal\vsite\Plugin\VsiteContextManager::vsiteFlushCssJs + * @covers ::cp_appearance_cp_custom_theme_update + * + * @throws \Behat\Mink\Exception\ElementNotFoundException + * @throws \Drupal\Core\Entity\EntityStorageException + */ + public function test(): void { + // Setup. + /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ + $vsite_context_manager = $this->container->get('vsite.context_manager'); + /** @var \Drupal\Core\State\StateInterface $state */ + $state = $this->container->get('state'); + + $this->visitViaVsite('cp/appearance/themes/custom-themes/add', $this->group); + $this->getSession()->getPage()->fillField('Custom Theme Name', 'The Doors'); + $this->assertSession()->waitForElementVisible('css', '.machine-name-value'); + $this->getSession()->getPage()->selectFieldOption('Parent Theme', 'clean'); + $this->getSession()->getPage()->findField('styles')->setValue('body { color: gray; }'); + $this->getSession()->getPage()->findField('scripts')->setValue("console.log('People Are Strange')"); + $this->getSession()->getPage()->pressButton('Save and set as default theme'); + $this->getSession()->getPage()->pressButton('Confirm'); + + $vsite_context_manager->activateVsite($this->group); + /** @var \Drupal\cp_appearance\Entity\CustomThemeInterface $custom_theme */ + $custom_theme = CustomTheme::load(CustomTheme::CUSTOM_THEME_ID_PREFIX . $this->group->id() . '_' . 'the_doors'); + $this->assertNotNull($custom_theme); + + // Record the original cache busters. + $this->drupalLogout(); + $this->visitViaVsite('', $this->group); + $original_style_cache = $this->getCustomThemeStyleCacheBuster($custom_theme); + $original_script_cache = $this->getCustomThemeScriptCacheBuster($custom_theme); + + // Make modifications. + $default_css_js_query_string_before_update = $state->get('system.css_js_query_string'); + $this->drupalLogin($this->groupAdmin); + $this->visitViaVsite("cp/appearance/themes/custom-themes/{$custom_theme->id()}/edit", $this->group); + $this->getSession()->getPage()->findField('styles')->setValue('body { color: black; font-family: Sans-Serif; };'); + $this->getSession()->getPage()->findField('scripts')->setValue("console.log('Riders On The Storm')"); + $this->getSession()->getPage()->pressButton('Save'); + $default_css_js_query_string_after_update = $state->get('system.css_js_query_string'); + + // Test. + $this->drupalLogout(); + $this->visitViaVsite('', $this->group); + $updated_style_cache = $this->getCustomThemeStyleCacheBuster($custom_theme); + $updated_script_cache = $this->getCustomThemeScriptCacheBuster($custom_theme); + + $this->assertNotEquals($original_style_cache, $updated_style_cache); + $this->assertNotEquals($original_script_cache, $updated_script_cache); + + $vsite_css_js_query_string = $state->get("vsite.css_js_query_string.{$this->group->id()}"); + $this->assertEquals($vsite_css_js_query_string, $updated_style_cache); + $this->assertEquals($vsite_css_js_query_string, $updated_script_cache); + $this->assertEquals($default_css_js_query_string_before_update, $default_css_js_query_string_after_update); + + // Cleanup. + $custom_theme->delete(); + /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ + $theme_handler = $this->container->get('theme_handler'); + $theme_handler->refreshInfo(); + } + + /** + * Returns the style cache buster for a custom theme. + * + * @param \Drupal\cp_appearance\Entity\CustomThemeInterface $custom_theme + * The custom theme. + * + * @return string + * The cache buster. + */ + protected function getCustomThemeStyleCacheBuster(CustomThemeInterface $custom_theme): string { + /** @var \Behat\Mink\Element\NodeElement $style_selector */ + $style_selector = $this->getSession()->getPage()->find('css', "[href*=\"/themes/custom_themes/{$custom_theme->id()}/style.css\"]"); + + /** @var string $style_path */ + $style_path = $style_selector->getAttribute('href'); + list(, $cache_id) = explode('?', $style_path); + + return $cache_id; + } + + /** + * Returns the script cache buster for a custom theme. + * + * @param \Drupal\cp_appearance\Entity\CustomThemeInterface $custom_theme + * The custom theme. + * + * @return string + * The cache buster. + */ + protected function getCustomThemeScriptCacheBuster(CustomThemeInterface $custom_theme): string { + /** @var \Behat\Mink\Element\NodeElement $script_selector */ + $script_selector = $this->getSession()->getPage()->find('css', "[src*=\"/themes/custom_themes/{$custom_theme->id()}/script.js\"]"); + + /** @var string $script_path */ + $script_path = $script_selector->getAttribute('src'); + list(, $cache_id) = explode('?', $script_path); + + return $cache_id; + } + + /** + * {@inheritdoc} + */ + public function tearDown() { + parent::tearDown(); + $this->cleanUpProperties(\self::class); + } + +} diff --git a/profile/modules/cp/modules/cp_appearance/tests/src/Unit/CssCollectionRendererTest.php b/profile/modules/cp/modules/cp_appearance/tests/src/Unit/CssCollectionRendererTest.php new file mode 100644 index 00000000000..acdf21c0f3a --- /dev/null +++ b/profile/modules/cp/modules/cp_appearance/tests/src/Unit/CssCollectionRendererTest.php @@ -0,0 +1,177 @@ +coreCssCollectionRenderer = $this->createMock(CoreCssCollectionRenderer::class); + $this->state = $this->createMock(State::class); + $this->vsiteContextManager = $this->createMock(VsiteContextManager::class); + $this->vsite = $this->createMock(Group::class); + } + + /** + * Assets and Rendered provider. + * + * @return array + * Test data. + */ + public function assetRenderProvider(): array { + return [ + [ + [ + [ + 'type' => 'file', + 'data' => 'public://css/css_dump_1.css', + 'preprocessed' => TRUE, + ], + [ + 'type' => 'file', + 'data' => 'public://css/css_dump_2.css', + 'preprocessed' => TRUE, + ], + ], + [ + [ + '#type' => 'html_tag', + '#tag' => 'link', + '#attributes' => [ + 'rel' => 'stylesheet', + 'media' => 'all', + 'href' => '/sites/default/files/css/css_dump_1.css', + ], + ], + [ + '#type' => 'html_tag', + '#tag' => 'link', + '#attributes' => [ + 'rel' => 'stylesheet', + 'media' => 'all', + 'href' => '/sites/default/files/css/css_dump_2.css', + ], + ], + ], + ], + ]; + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testOutsideVsite($assets, $elements): void { + $this->coreCssCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn(NULL); + + $cp_appearance_css_collection_renderer = new CssCollectionRenderer($this->coreCssCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_css_collection_renderer->render($assets); + + $this->assertArrayEquals($elements, $rendered_elements); + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testInsideVsiteNoCustomTheme($assets, $elements): void { + $this->coreCssCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn($this->vsite); + + $cp_appearance_css_collection_renderer = new CssCollectionRenderer($this->coreCssCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_css_collection_renderer->render($assets); + + $this->assertArrayEquals($elements, $rendered_elements); + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testOutsideVsiteWithCustomTheme($assets, $elements): void { + $assets[] = [ + 'type' => 'file', + 'data' => 'themes/custom_themes/os_ct_theme_id/style.css', + 'preprocessed' => FALSE, + ]; + + $elements[] = [ + '#type' => 'html_tag', + '#tag' => 'link', + '#attributes' => [ + 'rel' => 'stylesheet', + 'media' => 'all', + 'href' => '/themes/custom_themes/os_ct_theme_id/style.css?cache_buster_orig', + ], + ]; + + $is_cache_updated = FALSE; + + $this->coreCssCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn($this->vsite); + $this->vsite->method('id')->willReturn(47); + $this->state->method('get')->with('vsite.css_js_query_string.47')->willReturn('cache_buster_new'); + + $cp_appearance_css_collection_renderer = new CssCollectionRenderer($this->coreCssCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_css_collection_renderer->render($assets); + + foreach ($rendered_elements as $element) { + $is_cache_updated = (strpos($element['#attributes']['href'], 'cache_buster_new') !== FALSE); + } + + $this->assertTrue($is_cache_updated); + } + +} diff --git a/profile/modules/cp/modules/cp_appearance/tests/src/Unit/JsCollectionRendererTest.php b/profile/modules/cp/modules/cp_appearance/tests/src/Unit/JsCollectionRendererTest.php new file mode 100644 index 00000000000..0ebe4f781f0 --- /dev/null +++ b/profile/modules/cp/modules/cp_appearance/tests/src/Unit/JsCollectionRendererTest.php @@ -0,0 +1,192 @@ +coreJsCollectionRenderer = $this->createMock(CoreCssCollectionRenderer::class); + $this->state = $this->createMock(State::class); + $this->vsiteContextManager = $this->createMock(VsiteContextManager::class); + $this->vsite = $this->createMock(Group::class); + } + + /** + * Assets and Rendered provider. + * + * @return array + * Test data. + */ + public function assetRenderProvider(): array { + return [ + [ + 'drupalSettings' => [ + [ + 'type' => 'setting', + 'data' => [ + 'path' => [ + 'baseUrl' => '/', + ], + 'otherBands' => 'lb', + ], + ], + [ + 'type' => 'file', + 'minified' => TRUE, + 'data' => 'public://js/js_dump_1.js', + 'preprocess' => TRUE, + ], + [ + 'type' => 'file', + 'minified' => TRUE, + 'data' => 'public://js/js_dump_2.js', + 'preprocess' => TRUE, + ], + ], + [ + [ + '#type' => 'html_tag', + '#tag' => 'script', + '#value' => '{"path": {"baseUrl": "/"}, "otherBands": "lb"}', + '#attributes' => [ + 'type' => 'application/json', + 'data-drupal-selector' => 'drupal-settings-json', + ], + ], + [ + '#type' => 'html_tag', + '#tag' => 'script', + '#attributes' => [ + 'src' => '/sites/default/files/js/js_dump_1.js', + ], + ], + [ + '#type' => 'html_tag', + '#tag' => 'script', + '#attributes' => [ + 'src' => '/sites/default/files/js/js_dump_2.js', + ], + ], + ], + ], + ]; + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testOutsideVsite($assets, $elements): void { + $this->coreJsCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn(NULL); + + $cp_appearance_js_collection_renderer = new JsCollectionRenderer($this->coreJsCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_js_collection_renderer->render($assets); + + $this->assertArrayEquals($elements, $rendered_elements); + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testInsideVsiteNoCustomTheme($assets, $elements): void { + $this->coreJsCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn($this->vsite); + + $cp_appearance_js_collection_renderer = new JsCollectionRenderer($this->coreJsCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_js_collection_renderer->render($assets); + + $this->assertArrayEquals($elements, $rendered_elements); + } + + /** + * @covers ::render + * + * @dataProvider assetRenderProvider + */ + public function testOutsideVsiteWithCustomTheme($assets, $elements): void { + $assets[] = [ + 'type' => 'file', + 'minified' => FALSE, + 'data' => 'themes/custom_themes/os_ct_theme_id/script.js', + 'preprocess' => FALSE, + ]; + + $elements[] = [ + '#type' => 'html_tag', + '#tag' => 'script', + '#attributes' => [ + 'src' => '/themes/custom_themes/os_ct_theme_id/script.js?cache_buster_orig', + ], + ]; + + $is_cache_updated = FALSE; + + $this->coreJsCollectionRenderer->method('render')->with($assets)->willReturn($elements); + $this->vsiteContextManager->method('getActiveVsite')->willReturn($this->vsite); + $this->vsite->method('id')->willReturn(47); + $this->state->method('get')->with('vsite.css_js_query_string.47')->willReturn('cache_buster_new'); + + $cp_appearance_js_collection_renderer = new JsCollectionRenderer($this->coreJsCollectionRenderer, $this->state, $this->vsiteContextManager); + + $rendered_elements = $cp_appearance_js_collection_renderer->render($assets); + + foreach ($rendered_elements as $element) { + $is_cache_updated = (isset($element['#attributes']['src']) && (strpos($element['#attributes']['src'], 'cache_buster_new') !== FALSE)); + } + + $this->assertTrue($is_cache_updated); + } + +} diff --git a/profile/modules/custom/os_fullcalendar/tests/src/ExistingSiteJavascript/EventOsFullCalendarTest.php b/profile/modules/custom/os_fullcalendar/tests/src/ExistingSiteJavascript/EventOsFullCalendarTest.php index 1830613dd8a..5eef2a8b8d0 100644 --- a/profile/modules/custom/os_fullcalendar/tests/src/ExistingSiteJavascript/EventOsFullCalendarTest.php +++ b/profile/modules/custom/os_fullcalendar/tests/src/ExistingSiteJavascript/EventOsFullCalendarTest.php @@ -24,7 +24,7 @@ public function testOsFullCalendarLibraryLoad() { try { $web_assert->statusCodeEquals(200); - $web_assert->responseContains('os_fullcalendar.fullcalendar.js'); + $web_assert->elementExists('css', '.fullcalendar'); $this->assertTrue(TRUE); } catch (ExpectationException $e) { diff --git a/profile/modules/os/modules/os_theme_preview/tests/src/ExistingSite/PreviewActionOsThemePreviewTest.php b/profile/modules/os/modules/os_theme_preview/tests/src/ExistingSite/PreviewActionOsThemePreviewTest.php index 16879fa0b30..4dd7af307ee 100644 --- a/profile/modules/os/modules/os_theme_preview/tests/src/ExistingSite/PreviewActionOsThemePreviewTest.php +++ b/profile/modules/os/modules/os_theme_preview/tests/src/ExistingSite/PreviewActionOsThemePreviewTest.php @@ -86,11 +86,13 @@ public function testVisibility(): void { * @throws \Behat\Mink\Exception\ExpectationException */ public function testSave(): void { + /** @var \Drupal\Core\Theme\ThemeManagerInterface $theme_manager */ + $theme_manager = $this->container->get('theme.manager'); $this->visit('/os-theme-preview/cp/appearance/themes/preview/documental'); $this->getCurrentPage()->pressButton('Save'); - $this->visit('/os-theme-preview'); - $this->assertSession()->responseContains('/profiles/contrib/openscholar/themes/documental/css/style.css'); + $this->vsiteContextManager->activateVsite($this->group); + $this->assertEquals('documental', $theme_manager->getActiveTheme()->getName()); // This is part of the cleanup. // If this is not done, then it leads to deadlock errors in Travis diff --git a/profile/modules/vsite/src/Plugin/VsiteContextManager.php b/profile/modules/vsite/src/Plugin/VsiteContextManager.php index e15f8ae4868..303e117047e 100644 --- a/profile/modules/vsite/src/Plugin/VsiteContextManager.php +++ b/profile/modules/vsite/src/Plugin/VsiteContextManager.php @@ -3,6 +3,7 @@ namespace Drupal\vsite\Plugin; use Drupal\Core\Database\Connection; +use Drupal\Core\State\State; use Drupal\group\Entity\GroupInterface; use Drupal\vsite\Event\VsiteActivatedEvent; use Drupal\vsite\VsiteEvents; @@ -16,6 +17,8 @@ */ class VsiteContextManager implements VsiteContextManagerInterface { + public const VSITE_CSS_JS_QUERY_STRING_STATE_KEY_PREFIX = 'vsite.css_js_query_string.'; + /** * The active vsite. * @@ -117,6 +120,8 @@ public function getActiveVsiteAbsoluteUrl(string $path = ''): string { /** * {@inheritdoc} */ - public function getStorage(GroupInterface $group = NULL) {} + public static function vsiteFlushCssJs(GroupInterface $vsite): void { + \Drupal::state()->set(self::VSITE_CSS_JS_QUERY_STRING_STATE_KEY_PREFIX . $vsite->id(), base_convert(\Drupal::time()->getCurrentTime(), 10, 36)); + } } diff --git a/profile/modules/vsite/src/Plugin/VsiteContextManagerInterface.php b/profile/modules/vsite/src/Plugin/VsiteContextManagerInterface.php index fca98cf3db5..9ac4fd70777 100644 --- a/profile/modules/vsite/src/Plugin/VsiteContextManagerInterface.php +++ b/profile/modules/vsite/src/Plugin/VsiteContextManagerInterface.php @@ -41,4 +41,15 @@ public function getActivePurl(); */ public function getActiveVsiteAbsoluteUrl(string $path = ''): string; + /** + * Changes the dummy query string added to CSS and JS files of a vsite. + * + * Changing the dummy query string appended to CSS and JavaScript files forces + * all browsers to reload fresh files. + * + * @param \Drupal\group\Entity\GroupInterface $vsite + * The vsite. + */ + public static function vsiteFlushCssJs(GroupInterface $vsite): void; + } diff --git a/profile/modules/vsite/tests/src/ExistingSite/VsiteContextManagerTest.php b/profile/modules/vsite/tests/src/ExistingSite/VsiteContextManagerTest.php index a11bdb95e36..6e57bd785df 100644 --- a/profile/modules/vsite/tests/src/ExistingSite/VsiteContextManagerTest.php +++ b/profile/modules/vsite/tests/src/ExistingSite/VsiteContextManagerTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\vsite\ExistingSite; use Drupal\group\Entity\Group; +use Drupal\vsite\Plugin\VsiteContextManager; /** * VsiteContextManagerTest. @@ -83,4 +84,19 @@ public function testGetActivePurl() { $this->assertEquals('test-alias', $this->vsiteContextManager->getActivePurl()); } + /** + * @covers \Drupal\vsite\Plugin\VsiteContextManager::vsiteFlushCssJs + */ + public function testVsiteFlushCssJs(): void { + /** @var \Drupal\Core\State\StateInterface $state */ + $state = $this->container->get('state'); + + VsiteContextManager::vsiteFlushCssJs($this->group); + + $vsite_css_js_query_string = $state->get("vsite.css_js_query_string.{$this->group->id()}"); + + $this->assertNotNull($vsite_css_js_query_string); + $this->assertInternalType('string', $vsite_css_js_query_string); + } + } From 4d2a37874e2e7bef2169e4205938475d86070668 Mon Sep 17 00:00:00 2001 From: Saurabh Pandit <58168562+saurabh-axl@users.noreply.github.com> Date: Tue, 25 Feb 2020 21:05:04 +0530 Subject: [PATCH 08/58] 12831 import blog (#13088) * Issue #12831 - 12831 Blog import * Issue #12831 - Added validation for Blog Import * Issue #12831 - Removed mandatory validation for body field * Issue #12831 - PR changes * Issue #12831 - Changed blog csv template * Issue #12831 - Import Blog migrate test case * Issue #12831 - Import Blog PR changes * Issue #12831 - Added factory tests * Issue #12831 - CSV encoding issue * Issue #12831 - Timestamp error in import blog test --- profile/modules/apps/os_blog/migrations/os_blog_import.yml | 2 +- .../modules/cp/modules/cp_import/import_templates/os_blog.csv | 2 +- .../modules/cp_import/tests/src/ExistingSite/CpImportTest.php | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/profile/modules/apps/os_blog/migrations/os_blog_import.yml b/profile/modules/apps/os_blog/migrations/os_blog_import.yml index 070c76ab4e1..d80258126d2 100644 --- a/profile/modules/apps/os_blog/migrations/os_blog_import.yml +++ b/profile/modules/apps/os_blog/migrations/os_blog_import.yml @@ -5,7 +5,7 @@ label: 'CSV file migration' source: plugin: csv path: public://importcsv/os_blog.csv - ids: [Title, Path] + ids: [Timestamp, Title, Path] constants: view: '/blog/' process: diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv b/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv index 48ead6ca6a6..0fec7f9e24d 100644 --- a/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv +++ b/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv @@ -1,2 +1,2 @@ Title,Body,Files,Created date,Path -Blog title,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,my-blog \ No newline at end of file +Blog title,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,my-blog diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php index fb42f28d2d7..18291048246 100644 --- a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php @@ -397,6 +397,7 @@ public function testCpImportMigrationBlog() { $filename = drupal_get_path('module', 'cp_import_csv_test') . '/artifacts/blog.csv'; // Replace existing source file. $path = 'public://importcsv'; + $this->cpImportHelper->csvToArray($filename, 'utf-8'); $this->fileSystem->delete($path . '/os_blog.csv'); $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY); file_save_data(file_get_contents($filename), $path . '/os_blog.csv', FileSystemInterface::EXISTS_REPLACE); From 593588428f420865920cd61a7d0bd49eb42541b7 Mon Sep 17 00:00:00 2001 From: Uttkarsh Tiwari <38376852+uttkarsh-26@users.noreply.github.com> Date: Wed, 26 Feb 2020 10:48:25 +0530 Subject: [PATCH 09/58] Issue #12975 - Handle incorrect xml (#13096) * Issue #12921 - Update bibcite to latest dev to fix Authors not appearing issue and support for coded year import. * Issue #12921 - Test failures due to AccessHelper fix. * Issue #12921 - Test fixes. * Issue #12975 - Better handling of bad XML files. --- .../src/Plugin/App/PublicationsApp.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/profile/modules/apps/os_publications/src/Plugin/App/PublicationsApp.php b/profile/modules/apps/os_publications/src/Plugin/App/PublicationsApp.php index c247e5c7e98..65e6d1fd6f6 100644 --- a/profile/modules/apps/os_publications/src/Plugin/App/PublicationsApp.php +++ b/profile/modules/apps/os_publications/src/Plugin/App/PublicationsApp.php @@ -10,6 +10,7 @@ use Drupal\file\Entity\File; use Drupal\migrate\Plugin\MigrationPluginManager; use Drupal\vsite\Plugin\AppPluginBase; +use SimpleXMLElement; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Serializer\SerializerInterface; @@ -166,6 +167,20 @@ public function validateImportSource(array $form, FormStateInterface $formState) // Read contents of the file as a string. $data = file_get_contents($file->getFileUri()); + + // Validate the file beforehand if pubmed xml to prevent site from breaking. + if (strpos($file->getMimeType(), 'xml') !== FALSE) { + try { + new SimpleXMLElement($data); + } + catch (\Exception $e) { + // Display only user friendly error messages. If we don't clear, system + // displays whole lot of technical errors. + $this->messenger->deleteAll(); + $formState->setError($form['import_file'], $this->t('Could not parse file as PubMed XML.')); + return FALSE; + } + } // Get the data array. $decoded = $this->serializer->decode($data, $format); From e8d99281a882d71f7d31defdb11adcc4cef55757 Mon Sep 17 00:00:00 2001 From: Shashikanth Reddy Palvatla <25389431+shashikanth171@users.noreply.github.com> Date: Wed, 26 Feb 2020 20:29:14 +0530 Subject: [PATCH 10/58] Issue #12949 - Do not include OS Admin theme in selection list for creating a vsite. (#13046) * Issue #12949 - Added vsite_theme attribute to themes. * Issue #12949 - Updated tests to inlcude os admin theme. --- .../cp/modules/cp_appearance/src/AppearanceSettingsBuilder.php | 3 ++- .../tests/src/ExistingSite/AppearanceSettingsBuilderTest.php | 1 + profile/themes/adams/adams.info.yml | 1 + profile/themes/blue_sky/blue_sky.info.yml | 1 + profile/themes/branded_theme/branded_theme.info.yml | 1 + profile/themes/cabot/cabot.info.yml | 1 + profile/themes/clean/clean.info.yml | 1 + profile/themes/clean_blue/clean_blue.info.yml | 1 + profile/themes/dark/dark.info.yml | 1 + profile/themes/documental/documental.info.yml | 1 + profile/themes/everett/everett.info.yml | 1 + profile/themes/golden_accents/golden_accents.info.yml | 1 + profile/themes/holyoke/holyoke.info.yml | 1 + profile/themes/hwpi_classic/hwpi_classic.info.yml | 1 + profile/themes/hwpi_college/hwpi_college.info.yml | 1 + profile/themes/hwpi_lamont/hwpi_lamont.info.yml | 1 + profile/themes/hwpi_sterling/hwpi_sterling.info.yml | 1 + .../hwpi_themeone_bentley/hwpi_themeone_bentley.info.yml | 1 + profile/themes/hwpi_widener/hwpi_widener.info.yml | 1 + profile/themes/indigo/indigo.info.yml | 1 + profile/themes/ivy_accents/ivy_accents.info.yml | 1 + profile/themes/kirkland/kirkland.info.yml | 1 + profile/themes/lemon_sand/lemon_sand.info.yml | 1 + profile/themes/loeb/loeb.info.yml | 1 + profile/themes/mather/mather.info.yml | 1 + profile/themes/modern/modern.info.yml | 1 + profile/themes/monochrome/monochrome.info.yml | 1 + profile/themes/monument/monument.info.yml | 1 + profile/themes/onepage/onepage.info.yml | 1 + profile/themes/peabody/peabody.info.yml | 1 + profile/themes/red_raven/red_raven.info.yml | 1 + profile/themes/saffron_accents/saffron_accents.info.yml | 1 + profile/themes/shade/shade.info.yml | 1 + profile/themes/shadow/shadow.info.yml | 1 + profile/themes/slate/slate.info.yml | 1 + profile/themes/smart/smart.info.yml | 1 + profile/themes/soft/soft.info.yml | 1 + profile/themes/teal_accents/teal_accents.info.yml | 1 + profile/themes/themeone/themeone.info.yml | 1 + profile/themes/vibrant/vibrant.info.yml | 1 + profile/themes/white/white.info.yml | 1 + profile/themes/winthrop/winthrop.info.yml | 1 + 42 files changed, 43 insertions(+), 1 deletion(-) diff --git a/profile/modules/cp/modules/cp_appearance/src/AppearanceSettingsBuilder.php b/profile/modules/cp/modules/cp_appearance/src/AppearanceSettingsBuilder.php index f12b4d625ee..d7304bcff39 100644 --- a/profile/modules/cp/modules/cp_appearance/src/AppearanceSettingsBuilder.php +++ b/profile/modules/cp/modules/cp_appearance/src/AppearanceSettingsBuilder.php @@ -354,7 +354,8 @@ protected function prepareThemes(array &$themes): void { protected function osInstalledThemes(): array { if (!$this->osInstalledThemes) { $this->osInstalledThemes = array_filter($this->themeHandler->listInfo(), function (Extension $theme) { - return (isset($theme->base_themes) && $theme->status && $theme->origin != 'core') && $theme->info['base theme'] != 'bootstrap'; + return (isset($theme->base_themes) && $theme->status && $theme->origin != 'core') && $theme->info['base theme'] != 'bootstrap' && + isset($theme->info['vsite_theme']); }); } return $this->osInstalledThemes; diff --git a/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsBuilderTest.php b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsBuilderTest.php index bab5bba27df..22a4efa2961 100644 --- a/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsBuilderTest.php +++ b/profile/modules/cp/modules/cp_appearance/tests/src/ExistingSite/AppearanceSettingsBuilderTest.php @@ -123,6 +123,7 @@ public function testOnePageThemes(): void { $this->assertTrue(isset($themes['onepage'])); $this->assertFalse(isset($themes['stark'])); $this->assertFalse(isset($themes['seven'])); + $this->assertFalse(isset($themes['os_admin'])); $this->assertFalse(isset($themes['os_base'])); $this->assertFalse(isset($themes['bootstrap'])); diff --git a/profile/themes/adams/adams.info.yml b/profile/themes/adams/adams.info.yml index 0e61480c58a..7402a59619a 100644 --- a/profile/themes/adams/adams.info.yml +++ b/profile/themes/adams/adams.info.yml @@ -4,6 +4,7 @@ description: A dark grey and red flavor of college theme. base theme: hwpi_college core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/blue_sky/blue_sky.info.yml b/profile/themes/blue_sky/blue_sky.info.yml index fd2a104551e..855a84e74c6 100644 --- a/profile/themes/blue_sky/blue_sky.info.yml +++ b/profile/themes/blue_sky/blue_sky.info.yml @@ -4,6 +4,7 @@ description: Blue header and menu bar version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/branded_theme/branded_theme.info.yml b/profile/themes/branded_theme/branded_theme.info.yml index 6496f9a57aa..2317ca5e0ba 100644 --- a/profile/themes/branded_theme/branded_theme.info.yml +++ b/profile/themes/branded_theme/branded_theme.info.yml @@ -4,6 +4,7 @@ description: 'A modern looking theme for use by departments at Harvard.' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/cabot/cabot.info.yml b/profile/themes/cabot/cabot.info.yml index 68a481ad79d..e0ab8719d8c 100644 --- a/profile/themes/cabot/cabot.info.yml +++ b/profile/themes/cabot/cabot.info.yml @@ -4,6 +4,7 @@ description: Cabot is a blue & yellow version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/clean/clean.info.yml b/profile/themes/clean/clean.info.yml index 6b29be391be..d7a23f75403 100644 --- a/profile/themes/clean/clean.info.yml +++ b/profile/themes/clean/clean.info.yml @@ -4,6 +4,7 @@ description: 'Clean theme' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/clean_blue/clean_blue.info.yml b/profile/themes/clean_blue/clean_blue.info.yml index bac1d0df353..3ecc7b37a6f 100644 --- a/profile/themes/clean_blue/clean_blue.info.yml +++ b/profile/themes/clean_blue/clean_blue.info.yml @@ -4,6 +4,7 @@ description: 'Clean theme' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/dark/dark.info.yml b/profile/themes/dark/dark.info.yml index 0ab0c338fb0..f6f027926f6 100644 --- a/profile/themes/dark/dark.info.yml +++ b/profile/themes/dark/dark.info.yml @@ -4,6 +4,7 @@ description: 'Dark theme' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/documental/documental.info.yml b/profile/themes/documental/documental.info.yml index 6a24e193828..2a39d96a823 100644 --- a/profile/themes/documental/documental.info.yml +++ b/profile/themes/documental/documental.info.yml @@ -4,6 +4,7 @@ description: An ideal theme for documenting projects. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/everett/everett.info.yml b/profile/themes/everett/everett.info.yml index 1bf25841f42..074b305943a 100644 --- a/profile/themes/everett/everett.info.yml +++ b/profile/themes/everett/everett.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/golden_accents/golden_accents.info.yml b/profile/themes/golden_accents/golden_accents.info.yml index 773e8ccb3fe..b61274c09d2 100644 --- a/profile/themes/golden_accents/golden_accents.info.yml +++ b/profile/themes/golden_accents/golden_accents.info.yml @@ -4,6 +4,7 @@ description: 'Golden accents.' base theme: vibrant core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/holyoke/holyoke.info.yml b/profile/themes/holyoke/holyoke.info.yml index 652102d5d36..ee7cd04ad48 100644 --- a/profile/themes/holyoke/holyoke.info.yml +++ b/profile/themes/holyoke/holyoke.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_classic/hwpi_classic.info.yml b/profile/themes/hwpi_classic/hwpi_classic.info.yml index 7dcd6c55264..8aa47062d8c 100644 --- a/profile/themes/hwpi_classic/hwpi_classic.info.yml +++ b/profile/themes/hwpi_classic/hwpi_classic.info.yml @@ -4,6 +4,7 @@ description: A classic looking theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_college/hwpi_college.info.yml b/profile/themes/hwpi_college/hwpi_college.info.yml index d50c068eb44..6a0f6e09105 100644 --- a/profile/themes/hwpi_college/hwpi_college.info.yml +++ b/profile/themes/hwpi_college/hwpi_college.info.yml @@ -4,6 +4,7 @@ description: A college inspired theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_lamont/hwpi_lamont.info.yml b/profile/themes/hwpi_lamont/hwpi_lamont.info.yml index 890aada1e74..6f12fa47056 100644 --- a/profile/themes/hwpi_lamont/hwpi_lamont.info.yml +++ b/profile/themes/hwpi_lamont/hwpi_lamont.info.yml @@ -4,6 +4,7 @@ description: A stark looking theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_sterling/hwpi_sterling.info.yml b/profile/themes/hwpi_sterling/hwpi_sterling.info.yml index 83999ec4901..4a65bce981a 100644 --- a/profile/themes/hwpi_sterling/hwpi_sterling.info.yml +++ b/profile/themes/hwpi_sterling/hwpi_sterling.info.yml @@ -4,6 +4,7 @@ description: A stark looking theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_themeone_bentley/hwpi_themeone_bentley.info.yml b/profile/themes/hwpi_themeone_bentley/hwpi_themeone_bentley.info.yml index 0427b783e3b..a305ae62950 100644 --- a/profile/themes/hwpi_themeone_bentley/hwpi_themeone_bentley.info.yml +++ b/profile/themes/hwpi_themeone_bentley/hwpi_themeone_bentley.info.yml @@ -4,6 +4,7 @@ description: A classic looking theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/hwpi_widener/hwpi_widener.info.yml b/profile/themes/hwpi_widener/hwpi_widener.info.yml index c3d06ce4fe1..ed84b6eb558 100644 --- a/profile/themes/hwpi_widener/hwpi_widener.info.yml +++ b/profile/themes/hwpi_widener/hwpi_widener.info.yml @@ -4,6 +4,7 @@ description: A classic looking theme for use by departments at Harvard. base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/indigo/indigo.info.yml b/profile/themes/indigo/indigo.info.yml index 39bc7d2d699..353d29cee65 100644 --- a/profile/themes/indigo/indigo.info.yml +++ b/profile/themes/indigo/indigo.info.yml @@ -4,6 +4,7 @@ description: A dark blue nav bar version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/ivy_accents/ivy_accents.info.yml b/profile/themes/ivy_accents/ivy_accents.info.yml index f720f4ad010..41c3f313092 100644 --- a/profile/themes/ivy_accents/ivy_accents.info.yml +++ b/profile/themes/ivy_accents/ivy_accents.info.yml @@ -4,6 +4,7 @@ description: A ivy accent version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/kirkland/kirkland.info.yml b/profile/themes/kirkland/kirkland.info.yml index f13ab67c466..2e98bc645da 100644 --- a/profile/themes/kirkland/kirkland.info.yml +++ b/profile/themes/kirkland/kirkland.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/lemon_sand/lemon_sand.info.yml b/profile/themes/lemon_sand/lemon_sand.info.yml index 1d2ed4761c0..41ee6102591 100644 --- a/profile/themes/lemon_sand/lemon_sand.info.yml +++ b/profile/themes/lemon_sand/lemon_sand.info.yml @@ -4,6 +4,7 @@ description: A monochrome version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/loeb/loeb.info.yml b/profile/themes/loeb/loeb.info.yml index 879d5e5dbbf..1cdec4a39de 100644 --- a/profile/themes/loeb/loeb.info.yml +++ b/profile/themes/loeb/loeb.info.yml @@ -4,6 +4,7 @@ description: A loeb version of the Classic theme base theme: hwpi_sterling core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/mather/mather.info.yml b/profile/themes/mather/mather.info.yml index 7b5e30c52c5..75b5c57fa4e 100644 --- a/profile/themes/mather/mather.info.yml +++ b/profile/themes/mather/mather.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/modern/modern.info.yml b/profile/themes/modern/modern.info.yml index 93d3c923df9..3c642e377c6 100644 --- a/profile/themes/modern/modern.info.yml +++ b/profile/themes/modern/modern.info.yml @@ -4,6 +4,7 @@ description: 'A modern looking theme for use by departments at Harvard.' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/monochrome/monochrome.info.yml b/profile/themes/monochrome/monochrome.info.yml index 14313a431e1..25665af343e 100644 --- a/profile/themes/monochrome/monochrome.info.yml +++ b/profile/themes/monochrome/monochrome.info.yml @@ -4,6 +4,7 @@ description: A monochrome version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/monument/monument.info.yml b/profile/themes/monument/monument.info.yml index 56d24efa3dc..8e48b8d176a 100644 --- a/profile/themes/monument/monument.info.yml +++ b/profile/themes/monument/monument.info.yml @@ -4,6 +4,7 @@ description: 'A clean white version of the Modern theme' base theme: modern core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/onepage/onepage.info.yml b/profile/themes/onepage/onepage.info.yml index 842173dc77b..f1554802c94 100644 --- a/profile/themes/onepage/onepage.info.yml +++ b/profile/themes/onepage/onepage.info.yml @@ -5,6 +5,7 @@ base theme: os_base core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/peabody/peabody.info.yml b/profile/themes/peabody/peabody.info.yml index e60a7669f10..f3e4e01e6b9 100644 --- a/profile/themes/peabody/peabody.info.yml +++ b/profile/themes/peabody/peabody.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' diff --git a/profile/themes/red_raven/red_raven.info.yml b/profile/themes/red_raven/red_raven.info.yml index 0003f0e1360..896bed87ae9 100644 --- a/profile/themes/red_raven/red_raven.info.yml +++ b/profile/themes/red_raven/red_raven.info.yml @@ -4,6 +4,7 @@ description: A monochrome version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/saffron_accents/saffron_accents.info.yml b/profile/themes/saffron_accents/saffron_accents.info.yml index 421f98cf8fe..c7362f94ef4 100644 --- a/profile/themes/saffron_accents/saffron_accents.info.yml +++ b/profile/themes/saffron_accents/saffron_accents.info.yml @@ -4,6 +4,7 @@ description: 'A light color version of the Modern theme with saffron accents' base theme: modern core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/shade/shade.info.yml b/profile/themes/shade/shade.info.yml index e45ecc9fc3c..9601c2869c5 100644 --- a/profile/themes/shade/shade.info.yml +++ b/profile/themes/shade/shade.info.yml @@ -4,6 +4,7 @@ description: 'Shade.' base theme: vibrant core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/shadow/shadow.info.yml b/profile/themes/shadow/shadow.info.yml index b2511ef5a28..8c52ba4f3c2 100644 --- a/profile/themes/shadow/shadow.info.yml +++ b/profile/themes/shadow/shadow.info.yml @@ -4,6 +4,7 @@ description: 'Clean theme' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/slate/slate.info.yml b/profile/themes/slate/slate.info.yml index 6fce8a89396..31fb1175ea5 100644 --- a/profile/themes/slate/slate.info.yml +++ b/profile/themes/slate/slate.info.yml @@ -4,6 +4,7 @@ description: Slate blue/grey header and menu bar version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/smart/smart.info.yml b/profile/themes/smart/smart.info.yml index ac73e79a66f..42775c31d91 100644 --- a/profile/themes/smart/smart.info.yml +++ b/profile/themes/smart/smart.info.yml @@ -4,6 +4,7 @@ description: 'Smart theme' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/soft/soft.info.yml b/profile/themes/soft/soft.info.yml index e5bb1cd4b52..603a444ff50 100644 --- a/profile/themes/soft/soft.info.yml +++ b/profile/themes/soft/soft.info.yml @@ -4,6 +4,7 @@ description: 'Soft theme.' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/teal_accents/teal_accents.info.yml b/profile/themes/teal_accents/teal_accents.info.yml index 2a7aa044657..31e9f970f0b 100644 --- a/profile/themes/teal_accents/teal_accents.info.yml +++ b/profile/themes/teal_accents/teal_accents.info.yml @@ -4,6 +4,7 @@ description: A monochrome version of the Classic theme base theme: hwpi_classic core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/themeone/themeone.info.yml b/profile/themes/themeone/themeone.info.yml index 60d1c11e491..462df9ecc1a 100644 --- a/profile/themes/themeone/themeone.info.yml +++ b/profile/themes/themeone/themeone.info.yml @@ -4,6 +4,7 @@ description: 'Themeone theme.' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/vibrant/vibrant.info.yml b/profile/themes/vibrant/vibrant.info.yml index 90cc7a28cbb..dfa63fd24ca 100644 --- a/profile/themes/vibrant/vibrant.info.yml +++ b/profile/themes/vibrant/vibrant.info.yml @@ -4,6 +4,7 @@ description: 'A vibrant looking theme for use by departments at Harvard.' base theme: os_base core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/white/white.info.yml b/profile/themes/white/white.info.yml index f32b1aefeba..3383cda48da 100644 --- a/profile/themes/white/white.info.yml +++ b/profile/themes/white/white.info.yml @@ -4,6 +4,7 @@ description: 'A clean white version of the Classic theme' base theme: modern core: 8.x type: theme +vsite_theme: true regions: branding_header: 'Branding Header' diff --git a/profile/themes/winthrop/winthrop.info.yml b/profile/themes/winthrop/winthrop.info.yml index 2da3a5e111e..33a06efb36b 100644 --- a/profile/themes/winthrop/winthrop.info.yml +++ b/profile/themes/winthrop/winthrop.info.yml @@ -5,6 +5,7 @@ base theme: onepage core: 8.x type: theme onepage: true +vsite_theme: false regions: branding_header: 'Branding Header' From a30b9c56a411ae70a48ac28a00acfd13f3dc0423 Mon Sep 17 00:00:00 2001 From: Subhojit Paul Date: Thu, 27 Feb 2020 00:08:51 +0530 Subject: [PATCH 11/58] Issue #12947 - Cache Build and Install in travis (#12969) * Issue #cache - cache the composer/drupal install * Issue #cache - sync everything * Issue #12947 - Remove tests for debug reason * Issue #12947 - Install awscli in travis * Issue #12947 - Fix Install awscli in travis * Issue #12947 - Install pyenv * Issue #12947 - Upgrade dist * Issue #12947 - Debug travis * Issue #12947 - fix before install (wip) * Issue #12947 - fix aws credential (wip) * Issue #12947 - delete node_modules * Issue #12947 - delete node_modules 2 * Issue #12947 - Debug travis * Issue #12947 - Try tar and upload * Issue #12947 - Try tar and upload 2 * Issue #12947 - Debug travis * Issue #12947 - Debug travis * Issue #12947 - Debug travis * Issue #12947 - Debug travis * Issue #12947 - Upload only tar file * Issue #12947 - Debug travis * Issue #12947 - Fix path * Issue #12947 - Try to minimalize tar.gz * Issue #12947 - Enable more test and try xz tar * Issue #12947 - Upload xz and extend permissions * Issue #12947 - Fix path and dir * Issue #12947 - Replace zip to LZMA * Issue #12947 - Fix path * Issue #12947 - Debug sql file * Issue #12947 - Fix chrome name in travis * Issue #12947 - Try to speed up compression and remove chmod * Issue #12947 - Debug sql file in double place * Issue #12947 - Disable cache * Issue #12947 - Fix version consolidation/robo:2.0.0 * Issue #12947 - Print all logs * Issue #12947 - Test created SQL in same job * Issue #12947 - Debug composer install check * Issue #12947 - Debug check permission problem * Issue #12947 - Debug keep only permission extra, remove composer install * Issue #12947 - Debug add less permission * Issue #12947 - Debug add more permission * Issue #12947 - Include test configs into build * Issue #12947 - Move lines to Robo * Issue #12947 - Add composer install again * Issue #12947 - Fix composer install place * Issue #12947 - Fix Robo function and refactor return object * Issue #12947 - Fix Robo order * Issue #12947 - Fix Robo order 2 * Issue #12947 - Enable coding standards * Issue #12947 - Cache more * Issue #12947 - Extra comments * Issue #12944 - Enable 2 more tests * Issue #12944 - Replace chmod to chown (fix docker user) * Issue #12947 - Remove install db from unit test coverage * Issue #12947 - Add custom_themes dir * Issue #12947 - Add constans debug listing * Issue #12947 - create custom_themes xz * Issue #12947 - Enable all tests * Issue #12947 - Log only php and db * Issue #12947 - Refactor buildEnv and disable tests * Issue #12947 - Strange bug * Issue #12947 - Apply refactor * Issue #12947 - docker-compose pull is now performed in parallel by default * Issue #12947 - Remove sleep * Issue #12947 - Refactoring to upload only db, files and custom_themes, enable all tests Co-authored-by: Richard Brandon --- .travis.yml | 48 +++++++---- .travis/RoboFile.php | 165 ++++++++++++++++++++++++++++--------- .travis/docker-compose.yml | 1 + 3 files changed, 163 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index df421db808d..7992c508d67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: php -dist: trusty +dist: xenial cache: directories: - - $HOME/.composer/cache/files + - $HOME/.composer/cache addons: artifacts: @@ -23,26 +23,41 @@ env: - DRUPAL_BASE_URL="http://127.0.0.1:8080" - PATH="$PATH:$HOME/.composer/vendor/bin" - TRAVIS_NODE_VERSION="4" + - AWS_ACCESS_KEY_ID=$ARTIFACTS_KEY + - AWS_SECRET_ACCESS_KEY=$ARTIFACTS_SECRET stages: + - prepare for tests - test - name: codecov if: branch = 8.x-1.x-dev jobs: include: - - script: robo job:check-coding-standards - - script: robo job:run-unit-tests - - script: robo job:check-module-circular-dependency - - script: robo job:run-kernel-tests "widgets-1,widgets-2,widgets-3,widgets-4,widgets-5" - - script: robo job:run-kernel-tests "publications-1,publications-2,wysiwyg,vsite,os,os-theme-preview" - - script: robo job:run-kernel-tests "cp-1,cp-2,other-1,other-2,cp-menu,profiles,redirect,cp-appearance,os-search" - - script: robo job:run-functional-tests "classes,events,pages,cp,media-browser,os-theme-preview,breadcrumbs,cp-menu,vsite_favicon" - - script: robo job:run-functional-tests "os-search,analytics,publications,cp-appearance,redirect,twitter,os,vsite,cp-import" - - script: robo job:run-functional-javascript-tests "publications,mailchimp,metatag,redirect,cp-appearance,vsite-preset" - - script: robo job:run-functional-javascript-tests "os-search,cp,profiles,classes,pages" - - script: robo job:run-functional-javascript-tests "events,vsite,widgets" - - script: robo job:run-functional-javascript-tests "os,os-theme-preview,blog,faq,news,presentations,cp-menu" + - stage: prepare for tests + script: robo job:check-coding-standards + - stage: prepare for tests + script: robo job:run-unit-tests + - stage: prepare for tests + script: robo job:check-module-circular-dependency + - stage: test + script: robo job:run-kernel-tests "widgets-1,widgets-2,widgets-3,widgets-4,widgets-5" + - stage: test + script: robo job:run-kernel-tests "publications-1,publications-2,wysiwyg,vsite,os,os-theme-preview" + - stage: test + script: robo job:run-kernel-tests "cp-1,cp-2,other-1,other-2,cp-menu,profiles,redirect,cp-appearance,os-search" + - stage: test + script: robo job:run-functional-tests "classes,events,pages,cp,media-browser,os-theme-preview,breadcrumbs,cp-menu,vsite_favicon" + - stage: test + script: robo job:run-functional-tests "os-search,analytics,publications,cp-appearance,redirect,twitter,os,vsite,cp-import" + - stage: test + script: robo job:run-functional-javascript-tests "publications,mailchimp,metatag,redirect,cp-appearance,vsite-preset" + - stage: test + script: robo job:run-functional-javascript-tests "os-search,cp,profiles,classes,pages" + - stage: test + script: robo job:run-functional-javascript-tests "events,vsite,widgets" + - stage: test + script: robo job:run-functional-javascript-tests "os,os-theme-preview,blog,faq,news,presentations,cp-menu" - stage: codecov script: robo job:run-unit-tests-code-coverage after_success: bash <(curl -s https://codecov.io/bash) @@ -97,6 +112,9 @@ jobs: before_install: - echo 'sendmail_path = /bin/true' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - pyenv global 3.7.1 + - pip install -U pip + - pip install awscli install: - composer global require consolidation/robo:2.0.0 @@ -105,4 +123,6 @@ before_script: - cp .travis/RoboFile.php . after_failure: + - docker-compose logs php + - docker-compose logs mariadb - artifacts upload diff --git a/.travis/RoboFile.php b/.travis/RoboFile.php index 1c5202197fc..e4fe69c23a2 100644 --- a/.travis/RoboFile.php +++ b/.travis/RoboFile.php @@ -42,7 +42,8 @@ public function __construct() public function jobRunUnitTests($groups = '') { $collection = $this->collectionBuilder(); - $collection->addTaskList($this->buildEnvironment()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); $collection->addTaskList($this->runUnitTests($groups)); return $collection->run(); } @@ -56,7 +57,8 @@ public function jobRunUnitTests($groups = '') public function jobRunUnitTestsCodeCoverage($groups = '') { $collection = $this->collectionBuilder(); - $collection->addTaskList($this->buildEnvironment()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); $collection->addTaskList($this->enableXDebug()); $collection->addTaskList($this->runUnitTests($groups)); return $collection->run(); @@ -71,7 +73,8 @@ public function jobRunUnitTestsCodeCoverage($groups = '') public function jobCheckCodingStandards() { $collection = $this->collectionBuilder(); - $collection->addTaskList($this->buildEnvironment()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); $collection->addTaskList($this->runCheckCodingStandards()); return $collection->run(); } @@ -85,9 +88,12 @@ public function jobCheckCodingStandards() public function jobCheckModuleCircularDependency() { $collection = $this->collectionBuilder(); - $collection->addTaskList($this->buildEnvironment()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); $collection->addTaskList($this->installDrupal()); + $collection->addTaskList($this->uploadToAws()); $collection->addTaskList($this->runCheckModuleCircularDependency()); + $collection->addTaskList($this->installTestConfigs()); return $collection->run(); } @@ -101,7 +107,9 @@ public function jobRunKernelTests($groups = '') { $collection = $this->collectionBuilder(); $collection->addTaskList($this->buildEnvironment()); - $collection->addTaskList($this->installDrupal()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); + $collection->addTaskList($this->importDatabase()); $collection->addTaskList($this->installTestConfigs()); $collection->addTaskList($this->runKernelTests($groups)); return $collection->run(); @@ -117,7 +125,9 @@ public function jobRunKernelTestsCodeCoverage($groups = '') { $collection = $this->collectionBuilder(); $collection->addTaskList($this->buildEnvironment()); - $collection->addTaskList($this->installDrupal()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); + $collection->addTaskList($this->importDatabase()); $collection->addTaskList($this->installTestConfigs()); $collection->addTaskList($this->enableXDebug()); $collection->addTaskList($this->runKernelTests($groups)); @@ -136,7 +146,9 @@ public function jobRunFunctionalTests($groups = '') { $collection = $this->collectionBuilder(); $collection->addTaskList($this->buildEnvironment()); - $collection->addTaskList($this->installDrupal()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); + $collection->addTaskList($this->importDatabase()); $collection->addTaskList($this->installTestConfigs()); $collection->addTaskList($this->runFunctionalTests($groups)); return $collection->run(); @@ -154,7 +166,9 @@ public function jobRunFunctionalJavascriptTests($groups = '') { $collection = $this->collectionBuilder(); $collection->addTaskList($this->buildEnvironment()); - $collection->addTaskList($this->installDrupal()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->buildComposer()); + $collection->addTaskList($this->importDatabase()); $collection->addTaskList($this->installTestConfigs()); $collection->addTaskList($this->runFunctionalJavascriptTests($groups)); return $collection->run(); @@ -171,6 +185,8 @@ public function jobRunBehatTests() $collection = $this->collectionBuilder(); $collection->addTaskList($this->downloadDatabase()); $collection->addTaskList($this->buildEnvironment()); + $collection->addTaskList($this->buildDocker()); + $collection->addTaskList($this->importDatabase()); $collection->addTask($this->waitForDrupal()); $collection->addTaskList($this->runUpdatePath()); $collection->addTaskList($this->runBehatTests()); @@ -198,35 +214,111 @@ protected function downloadDatabase() return $tasks; } - /** - * Builds the Docker environment. - * - * @return \Robo\Task\Base\Exec[] - * An array of tasks. - */ - protected function buildEnvironment() - { - $force = true; - $tasks = []; - $tasks[] = $this->taskFilesystemStack() - ->copy('.travis/docker-compose.yml', 'docker-compose.yml', $force) - ->copy('.travis/traefik.yml', 'traefik.yml', $force) - ->copy('.travis/.env', '.env', $force) - ->copy('.travis/config/behat.yml', 'tests/behat.yml', $force); - - $tasks[] = $this->taskExec('echo AWS_ACCESS_KEY_ID=' . getenv('ARTIFACTS_KEY') . ' >> .env'); - $tasks[] = $this->taskExec('echo AWS_SECRET_ACCESS_KEY=' . getenv('ARTIFACTS_SECRET') . ' >> .env'); - $tasks[] = $this->taskExec('echo AWS_ES_ACCESS_ENDPOINT=' . getenv('ARTIFACTS_ES_ENDPOINT') . ' >> .env'); - $tasks[] = $this->taskExec('docker-compose --verbose pull --parallel'); - $tasks[] = $this->taskExec('docker-compose up -d'); - $tasks[] = $this->taskExec('docker-compose exec -T php composer global require hirak/prestissimo'); - $tasks[] = $this->taskExec('make'); - $tasks[] = $this->taskExec('docker-compose exec -T php cp .travis/config/phpunit.xml web/core/phpunit.xml'); - $tasks[] = $this->taskExec('docker-compose exec -T php cp .travis/config//bootstrap.php web/core/tests/bootstrap.php'); - $tasks[] = $this->taskExec('docker-compose exec -T php mkdir -p web/sites/simpletest'); + /** + * Creates the Docker environment. + * + * @return \Robo\Task\Base\Exec[] + * An array of tasks. + */ + protected function buildDocker() + { + $force = true; + $tasks = []; + $tasks[] = $this->taskFilesystemStack() + ->copy('.travis/docker-compose.yml', 'docker-compose.yml', $force) + ->copy('.travis/traefik.yml', 'traefik.yml', $force) + ->copy('.travis/.env', '.env', $force) + ->copy('.travis/config/behat.yml', 'tests/behat.yml', $force); + + $tasks[] = $this->taskExec('echo AWS_ACCESS_KEY_ID=' . getenv('ARTIFACTS_KEY') . ' >> .env'); + $tasks[] = $this->taskExec('echo AWS_SECRET_ACCESS_KEY=' . getenv('ARTIFACTS_SECRET') . ' >> .env'); + $tasks[] = $this->taskExec('echo AWS_ES_ACCESS_ENDPOINT=' . getenv('ARTIFACTS_ES_ENDPOINT') . ' >> .env'); + $tasks[] = $this->taskExec('docker-compose pull'); + $tasks[] = $this->taskExec('docker-compose up -d'); + + return $tasks; + } - return $tasks; - } + /** + * Build environment. + * + * @return \Robo\Task\Base\Exec[] + * An array of tasks. + */ + protected function buildEnvironment() + { + $tasks = []; + + $tasks[] = $this->taskExec('aws s3 sync s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER .'); + $tasks[] = $this->taskExec('tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz'); + $tasks[] = $this->taskExec('sudo chown -R 1000:1000 custom_themes'); + $tasks[] = $this->taskExec('ls -la'); + + return $tasks; + } + /** + * Import database. + * + * @return \Robo\Task\Base\Exec[] + * An array of tasks. + */ + protected function importDatabase() + { + $tasks = []; + + // Fix import issue. + $tasks[] = $this->taskExec('sudo tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-db.tar.xz web'); + $tasks[] = $this->taskExec('sudo tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-settings.tar.xz web/sites/default'); + $tasks[] = $this->taskExec('sudo tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-files.tar.xz web/sites/default'); + $tasks[] = $this->taskExec('sudo chown -R 1000:1000 web/sites/default'); + $tasks[] = $this->taskExec('ls -la'); + // Import sql. + $tasks[] = $this->taskExec('docker-compose exec -T php drush sqlq --file=./travis-backup.sql'); + + return $tasks; + } + + /** + * Create sql dump and compressed build and upload to S3. + * + * @return \Robo\Task\Base\Exec[] + * A collection of tasks. + */ + protected function uploadToAws() + { + $tasks[] = $this->taskExec('docker-compose exec -T php drush sql-dump --result-file=./travis-backup.sql'); + $tasks[] = $this->taskExec('ls -la'); + $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-db.tar.xz web/travis-backup.sql'); + $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-settings.tar.xz web/sites/default/settings.php'); + $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz custom_themes'); + $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-files.tar.xz web/sites/default/files'); + $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-db.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-db.tar.xz'); + $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-settings.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-settings.tar.xz'); + $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz'); + $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-files.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-files.tar.xz'); + + return $tasks; + } + + /** + * Builds the Code Base. + * + * @return \Robo\Task\Base\Exec[] + * An array of tasks. + */ + protected function buildComposer() + { + $force = true; + $tasks = []; + + $tasks[] = $this->taskExec('docker-compose exec -T php composer global require hirak/prestissimo'); + $tasks[] = $this->taskExec('make'); + $tasks[] = $this->taskExec('docker-compose exec -T php cp .travis/config/phpunit.xml web/core/phpunit.xml'); + $tasks[] = $this->taskExec('docker-compose exec -T php cp .travis/config//bootstrap.php web/core/tests/bootstrap.php'); + $tasks[] = $this->taskExec('docker-compose exec -T php mkdir -p web/sites/simpletest'); + + return $tasks; + } /** * Enables xdebug in the Docker environment. @@ -239,7 +331,6 @@ protected function enableXDebug() $tasks[] = $this->taskExecStack() ->exec('echo PHP_XDEBUG_ENABLED=1 >> .env') ->exec('docker-compose up -d'); - return $tasks; } diff --git a/.travis/docker-compose.yml b/.travis/docker-compose.yml index d8ff40527a5..adf9b609276 100644 --- a/.travis/docker-compose.yml +++ b/.travis/docker-compose.yml @@ -93,5 +93,6 @@ services: chrome: # Note: chrome 67/68 is giving errors so we pin to 65 for now. image: previousnext/chrome-headless:65 + container_name: "${PROJECT_NAME}_chrome" ports: - "9222:9222" From 911a282f85081cd19a619d631b08989fd828d73c Mon Sep 17 00:00:00 2001 From: Jiteshkhatwani <49042377+Jiteshkhatwani@users.noreply.github.com> Date: Thu, 27 Feb 2020 17:56:40 +0530 Subject: [PATCH 12/58] Issue #12950 - Fix - Vsite owner doesn't have access to cp item (#13091) * Issue #12950 - Added personal admin role to use who creates the group. * Issue #12950 - Removed static permission and added dynamic group type. * Issue #12950 - Added the test for admin links. * Issue #12950 - Removed overwriting of role and insteadd append the admin role to the owner. * Issue #12950 - Added assigning role logic to helper and created kernel test for that. * Issue #12950 - Refactored the code. * Issue #12950 - Resolved PR comments. * Issue #12950 - Changed invalid comment. * Issue #12950 - Changed comment. * Issue #12950 - Changed comment. * Issue #12950 - Removed helper from the test. * Issue #12950 - Chaged Assert True to Assert Contains, considering multiple roles. * Issue #12950 - Converted 2 dimensional array into single dimensional array. * Issue #12950 - Add group admin role removed when admin is creating the group. * Issue #12950 - Added helper in the test. --- .../VisiteMinimalDepartmentTest.php | 1 + .../modules/vsite_preset/vsite_preset.module | 8 +-- .../vsite/src/Helper/VsiteRoleHelper.php | 38 ++++++++++++++ .../src/Helper/VsiteRoleHelperInterface.php | 20 ++++++++ .../src/ExistingSite/VsiteRoleHelperTest.php | 51 +++++++++++++++++++ profile/modules/vsite/vsite.module | 16 ++++++ profile/modules/vsite/vsite.services.yml | 3 ++ 7 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 profile/modules/vsite/src/Helper/VsiteRoleHelper.php create mode 100644 profile/modules/vsite/src/Helper/VsiteRoleHelperInterface.php create mode 100644 profile/modules/vsite/tests/src/ExistingSite/VsiteRoleHelperTest.php diff --git a/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSiteJavascript/VisiteMinimalDepartmentTest.php b/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSiteJavascript/VisiteMinimalDepartmentTest.php index 9f33f30a8be..690f0df458f 100644 --- a/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSiteJavascript/VisiteMinimalDepartmentTest.php +++ b/profile/modules/vsite/modules/vsite_preset/tests/src/ExistingSiteJavascript/VisiteMinimalDepartmentTest.php @@ -54,6 +54,7 @@ public function testMinimalDepartmentPreset() { $this->vsitePresetHelper->createDefaultContent($this->group, $uri); } + // Check if created group type has home link. $web_assert = $this->assertSession(); $this->visitViaVsite('', $this->group); $web_assert->statusCodeEquals(200); diff --git a/profile/modules/vsite/modules/vsite_preset/vsite_preset.module b/profile/modules/vsite/modules/vsite_preset/vsite_preset.module index 7dd45111727..42de86ebbb1 100644 --- a/profile/modules/vsite/modules/vsite_preset/vsite_preset.module +++ b/profile/modules/vsite/modules/vsite_preset/vsite_preset.module @@ -17,6 +17,10 @@ use Symfony\Component\HttpFoundation\RedirectResponse; * Implements hook_group_insert() for all the tasks which are needed for setting up a new vsite. */ function vsite_preset_group_insert(GroupInterface $group) { + // Call helper to enable apps as per preset settings. + /** @var \Drupal\vsite_preset\Helper\VsitePresetHelper $preset_helper */ + $preset_helper = \Drupal::service('vsite_preset.preset_helper'); + if ($group->hasField('field_preset') && !$group->get('field_preset')->isEmpty()) { $preset_id = $group->get('field_preset')->get(0)->getValue()['target_id']; /** @var \Drupal\vsite_preset\Entity\GroupPreset $preset */ @@ -25,9 +29,7 @@ function vsite_preset_group_insert(GroupInterface $group) { // Gets apps list. $appsToEnable = $preset->getEnabledApps(); $appsToSetPrivate = $preset->getPrivateApps(); - // Call helper to enable apps as per preset settings. - /** @var \Drupal\vsite_preset\Helper\VsitePresetHelper $preset_helper */ - $preset_helper = \Drupal::service('vsite_preset.preset_helper'); + $preset_helper->enableApps($group, $appsToEnable, $appsToSetPrivate); $fileArr = $preset->getCreationFilePaths(); diff --git a/profile/modules/vsite/src/Helper/VsiteRoleHelper.php b/profile/modules/vsite/src/Helper/VsiteRoleHelper.php new file mode 100644 index 00000000000..a8bcdad0d94 --- /dev/null +++ b/profile/modules/vsite/src/Helper/VsiteRoleHelper.php @@ -0,0 +1,38 @@ +getOwner(); + + // Get the membership details of the owner. + $membership = $group->getMember($owner); + + // Get the roles of the owner. + $roles = $membership->getRoles(); + // Check whether the owner has admin role. + if (!isset($roles[$group->getGroupType()->id() . '-administrator'])) { + // No, so add the admin role to the membership + // Get the group_content entity. + $group_content = $membership->getGroupContent(); + // Set target group role. + $group_content->group_roles->appendItem(['target_id' => $group->getGroupType()->id() . '-administrator']); + // Save updated entity. + $group_content->save(); + } + } + +} diff --git a/profile/modules/vsite/src/Helper/VsiteRoleHelperInterface.php b/profile/modules/vsite/src/Helper/VsiteRoleHelperInterface.php new file mode 100644 index 00000000000..facd517c93b --- /dev/null +++ b/profile/modules/vsite/src/Helper/VsiteRoleHelperInterface.php @@ -0,0 +1,20 @@ +vsiteRoleHelper = $this->container->get('vsite.role_helper'); + // Setup group with department group type. + $this->group = $this->createGroup([ + 'type' => 'department', + 'field_preset' => 'os_department', + ]); + $this->vsiteContextManager->activateVsite($this->group); + } + + /** + * Tests owner is having administrator role. + */ + public function testVsiteGroupOwnerHasAdministratorRole() { + $group = $this->group; + // Get the group owner. + $owner = $group->getOwner(); + // Get the membership details of the owner. + $membership = $group->getMember($owner); + + // Helper to assign the admin if its coming from the front end. + $this->vsiteRoleHelper->assignGroupAdminRoleToOwner($group); + + // Current owner roles. + $owner_roles = $membership->getGroupContent()->get('group_roles')->getValue(); + + // Converting 2 dimensional array into single dimensional array. + $roles = []; + foreach ($owner_roles as $role) { + $roles[] = $role['target_id']; + } + $this->assertContains($group->getGroupType()->id() . '-administrator', $roles); + } + +} diff --git a/profile/modules/vsite/vsite.module b/profile/modules/vsite/vsite.module index afeabcbe24e..cc312becff9 100644 --- a/profile/modules/vsite/vsite.module +++ b/profile/modules/vsite/vsite.module @@ -444,3 +444,19 @@ function vsite_views_pre_render(ViewExecutable $view) { $os_widget_context->addApp($app); } } + +/** + * Implements hook_group_insert() for a new vsite. + */ +function vsite_group_insert(GroupInterface $group) { + // Call helper service. + /** @var \Drupal\vsite\Helper\VsiteRoleHelper $role_helper */ + $role_helper = \Drupal::service('vsite.role_helper'); + + $get_route_parameters = \Drupal::request()->attributes->all(); + // Admin role assignment is not required when creating from admin. + if (isset($get_route_parameters['_route']) && $get_route_parameters['_route'] === 'entity.group.create') { + // Assign admin role to owner. + $role_helper->assignGroupAdminRoleToOwner($group); + } +} diff --git a/profile/modules/vsite/vsite.services.yml b/profile/modules/vsite/vsite.services.yml index 2deaa083414..cdcb5e1c7b0 100644 --- a/profile/modules/vsite/vsite.services.yml +++ b/profile/modules/vsite/vsite.services.yml @@ -66,3 +66,6 @@ services: vsite.validate_helper: class: Drupal\vsite\Helper\VsiteFieldValidateHelper arguments: ['@vsite.context_manager', '@entity_type.manager'] + + vsite.role_helper: + class: \Drupal\vsite\Helper\VsiteRoleHelper From bce5c5e7fec95b9b9f73230a433bad49f8e22409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Thu, 27 Feb 2020 15:12:56 +0100 Subject: [PATCH 13/58] Issue #13104 - Hotfix for media browser issue (#13107) * Issue #13104 - Hotfix for media browser issue * Issue #13104 - Create a test to assert media browser dialog is working with exists media * Issue #13104 - Extra classes --- .../os/js/FileEditor/FileEditor.module.js | 2 +- .../modules/os_media/js/MediaBrowserModule.js | 2 +- .../modules/os_media/templates/browser.html | 6 +-- .../SelectMediaWithMediaBrowserTest.php | 49 +++++++++++++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 profile/modules/os/tests/src/ExistingSiteJavascript/SelectMediaWithMediaBrowserTest.php diff --git a/profile/modules/os/js/FileEditor/FileEditor.module.js b/profile/modules/os/js/FileEditor/FileEditor.module.js index e0ef12f7040..ecd048f3e9a 100644 --- a/profile/modules/os/js/FileEditor/FileEditor.module.js +++ b/profile/modules/os/js/FileEditor/FileEditor.module.js @@ -201,7 +201,7 @@ scope.onClose({saved: FER.CANCELED}); } - if (settings.fetchSetting('isBrowseMedia')) { + if (settings.isBrowseMedia !== undefined && settings.fetchSetting('isBrowseMedia')) { window.location.reload(); } diff --git a/profile/modules/os/modules/os_media/js/MediaBrowserModule.js b/profile/modules/os/modules/os_media/js/MediaBrowserModule.js index edfec6e46e6..2cfd6203132 100644 --- a/profile/modules/os/modules/os_media/js/MediaBrowserModule.js +++ b/profile/modules/os/modules/os_media/js/MediaBrowserModule.js @@ -901,7 +901,7 @@ modal.element.dialog(nparams.dialog); modal.close.then(function (result) { - if (settings.fetchSetting('isBrowseMedia')) { + if (settings.isBrowseMedia !== undefined && settings.fetchSetting('isBrowseMedia')) { window.location.reload(); } $('#upmedia').focus(); diff --git a/profile/modules/os/modules/os_media/templates/browser.html b/profile/modules/os/modules/os_media/templates/browser.html index cb0a303b730..27c64562f98 100644 --- a/profile/modules/os/modules/os_media/templates/browser.html +++ b/profile/modules/os/modules/os_media/templates/browser.html @@ -1,8 +1,8 @@
- - - + + +
diff --git a/profile/modules/os/tests/src/ExistingSiteJavascript/SelectMediaWithMediaBrowserTest.php b/profile/modules/os/tests/src/ExistingSiteJavascript/SelectMediaWithMediaBrowserTest.php new file mode 100644 index 00000000000..c8d67a9dd24 --- /dev/null +++ b/profile/modules/os/tests/src/ExistingSiteJavascript/SelectMediaWithMediaBrowserTest.php @@ -0,0 +1,49 @@ +createMedia(); + $this->group->addContent($media, "group_entity:media"); + $account = $this->createUser(); + $this->addGroupAdmin($account, $this->group); + + $web_assert = $this->assertSession(); + $this->drupalLogin($account); + $this->visitViaVsite('node/add/blog', $this->group); + $web_assert->statusCodeEquals(200); + // Wait for every javascript loaded. + $web_assert->waitForElementVisible('css', '.media-browser-drop-box'); + $web_assert->waitForElementVisible('css', '.cke_button__bold_icon'); + + // Open media browser dialog. + $this->getSession()->getPage()->clickLink('Upload'); + $web_assert->waitForElementVisible('css', '.media-browser-buttons'); + $web_assert->pageTextContains('Previously uploaded files'); + + // Select "Previously uploaded files" tab. + $this->getSession()->getPage()->find('css', '.media-browser-button--library')->click(); + // Select first media. + $this->getSession()->getPage()->find('css', '.media-row')->click(); + // Insert to field. + $this->getSession()->getPage()->pressButton('Insert'); + $this->waitForDialogClose(); + + // Assert media title is showed. + $web_assert->pageTextContains($media->label()); + } + +} From 0bb9491be320f59ca51b8934eed48a3c826aabfa Mon Sep 17 00:00:00 2001 From: Uttkarsh Tiwari <38376852+uttkarsh-26@users.noreply.github.com> Date: Fri, 28 Feb 2020 00:16:50 +0530 Subject: [PATCH 14/58] Issue #12921 - Editors fix and special characters coverage. (#13102) * Issue #12921 - Editors fix and special characters coverage. * Issue #12921 - Missing field mappings and bug fixes. * Issue #12921 - Missing field mappings and bug fixes. * Issue #12921 - Missing field mappings and bug fixes. --- config/sync/bibcite_entity.mapping.bibtex.yml | 6 +- .../src/CpImportLatexUnicodeMapping.php | 276 ++++++++++++++++++ .../src/Helper/CpImportPublicationHelper.php | 80 +++++ .../ExistingSite/CpImportPublicationsTest.php | 84 +++++- 4 files changed, 442 insertions(+), 4 deletions(-) create mode 100644 profile/modules/cp/modules/cp_import/src/CpImportLatexUnicodeMapping.php diff --git a/config/sync/bibcite_entity.mapping.bibtex.yml b/config/sync/bibcite_entity.mapping.bibtex.yml index fe9d35bfd7b..4f39c9eeb67 100644 --- a/config/sync/bibcite_entity.mapping.bibtex.yml +++ b/config/sync/bibcite_entity.mapping.bibtex.yml @@ -51,13 +51,13 @@ fields: keywords: keywords abstract: bibcite_abst_e year: bibcite_year - booktitle: '' + booktitle: bibcite_secondary_title journal: bibcite_secondary_title series: '' volume: bibcite_volume edition: bibcite_edition chapter: bibcite_section - number: bibcite_number + number: bibcite_issue pages: bibcite_pages month: bibcite_date institution: '' @@ -67,7 +67,7 @@ fields: address: bibcite_place_published issn: bibcite_issn isbn: bibcite_isbn - url: bibcite_url + url: publishers_version doi: bibcite_doi note: bibcite_notes language: bibcite_lang diff --git a/profile/modules/cp/modules/cp_import/src/CpImportLatexUnicodeMapping.php b/profile/modules/cp/modules/cp_import/src/CpImportLatexUnicodeMapping.php new file mode 100644 index 00000000000..0f74219b53d --- /dev/null +++ b/profile/modules/cp/modules/cp_import/src/CpImportLatexUnicodeMapping.php @@ -0,0 +1,276 @@ + "#", + "\\\\%" => "%", + "\\\\&" => "&", + "(? " ", + "\\{?\\\\textexclamdown\\}?" => "¡", + "\\{?\\\\textcent\\}?" => "¢", + "\\{?\\\\textsterling\\}?" => "£", + "\\{?\\\\textyen\\}?" => "¥", + "\\{?\\\\textbrokenbar\\}?" => "¦", + "\\{?\\\\textsection\\}?" => "§", + "\\{?\\\\textasciidieresis\\}?" => "¨", + "\\{?\\\\textcopyright\\}?" => "©", + "\\{?\\\\textordfeminine\\}?" => "ª", + "\\{?\\\\guillemotleft\\}?" => "«", + "\\{?\\\\textlnot\\}?" => "¬", + "\\{?\\\\textregistered\\}?" => "®", + "\\{?\\\\textasciimacron\\}?" => "¯", + "\\{?\\\\textdegree\\}?" => "°", + "\\{?\\\\textpm\\}?" => "±", + "\\{?\\\\texttwosuperior\\}?" => "²", + "\\{?\\\\textthreesuperior\\}?" => "³", + "\\{?\\\\textasciiacute\\}?" => "´", + "\\{?\\\\textmu\\}?" => "µ", + "\\{?\\\\textparagraph\\}?" => "¶", + "\\{?\\\\textperiodcentered\\}?" => "·", + "\\{?\\\\c\\\\ \\}?" => "¸", + "\\{?\\\\textonesuperior\\}?" => "¹", + "\\{?\\\\textordmasculine\\}?" => "º", + "\\{?\\\\guillemotright\\}?" => "»", + "\\{?\\\\textonequarter\\}?" => "¼", + "\\{?\\\\textonehalf\\}?" => "½", + "\\{?\\\\textthreequarters\\?}" => "¾", + "\\{?\\\\textquestiondown\\?}" => "¿", + "\\{?\\\\`\\{?A\\}?\\}?" => "À", + "\\{?\\\\'\\{?A\\}?\\}?" => "Á", + "\\{?\\\\\\^\\{?A\\}?\\}?" => "Â", + "\\{?\\\\~\\{?A\\}?\\}?" => "Ã", + "\\{?\\\\\"\\{?A\\}?\\}?" => "Ä", + "\\{?\\\\r\s\\{?A\\}?\\}?" => "Å", + "\\{?\\\\AE\\}?" => "Æ", + "\\{?\\\\c\sC\\}?" => "Ç", + "\\{?\\\\`\\{?E\\}?\\}?" => "È", + "\\{?\\\\'\\{?E\\}?\\}?" => "É", + "\\{?\\\\\\^\\{?E\\}?\\}?" => "Ê", + "\\{?\\\\\"\\{?E\\}?\\}?" => "Ë", + "\\{?\\\\`\\{?I\\}?\\}?" => "Ì", + "\\{?\\\\'\\{?I\\}?\\}?" => "Í", + "\\{?\\\\\\^\\{?I\\}?\\}?" => "Î", + "\\{?\\\\\"\\{?I\\}?\\}?" => "Ï", + "\\{?\\\\DH\\}?" => "Ð", + "\\{?\\\\~\\{?N\\}?\\}?" => "Ñ", + "\\{?\\\\`\\{?O\\}?\\}?" => "Ò", + "\\{?\\\\'\\{?O\\}?\\}?" => "Ó", + "\\{?\\\\\\^\\{?O\\}?\\}?" => "Ô", + "\\{?\\\\~\\{?O\\}?\\}?" => "Õ", + "\\{?\\\\\"\\{?O\\}?\\}?" => "Ö", + "\\{?\\\\texttimes\\}?" => "×", + "\\{?\\\\O\\}?" => "Ø", + "\\{?\\\\`\\{?U\\}?\\}?" => "Ù", + "\\{?\\\\'\\{?U\\}?\\}?" => "Ú", + "\\{?\\\\\\^\\{?U\\}?\\}?" => "Û", + "\\{?\\\\\"\\{?U\\}?\\}?" => "Ü", + "\\{?\\\\'\\{?Y\\}?\\}?" => "Ý", + "\\{?\\\\TH\\}?" => "Þ", + "\\{?\\\\ss\\{?\\}?\\}?" => "ß", + "\\{?\\\\`\\{?a\\}?\\}?" => "à", + "\\{?\\\\'\\{?a\\}?\\}?" => "á", + "\\{?\\\\\\^\\{?a\\}?\\}?" => "â", + "\\{?\\\\~\\{?a\\}?\\}?" => "ã", + "\\{?\\\\\"\\{?a\\}?\\}?" => "ä", + "\\{?\\\\r\s\\{?a\\}?\\}?" => "å", + "\\{?\\\\ae\\}?" => "æ", + "\\{?\\\\c\\{?c\\}?\\}?" => "ç", + "\\{?\\\\`\\{?e\\}?\\}?" => "è", + "\\{?\\\\'\\{?e\\}?\\}?" => "é", + "\\{?\\\\\\^\\{?e\\}?\\}?" => "ê", + "\\{?\\\\\"\s?\\{?e\\}?\\}?" => "ë", + "\\{?\\\\`\\{?i\\}?\\}?" => "ì", + "\\{?\\\\'\\{?i\\}?\\}?" => "í", + "\\{?\\\\\\^\\{?i\\}?\\}?" => "î", + "\\{?\\\\\"\\{?i\\}?\\}?" => "ï", + "\\{?\\\\dh\\}?" => "ð", + "\\{?\\\\~\\{?n\\}?\\}?" => "ñ", + "\\{?\\\\`\\{?o\\}?\\}?" => "ò", + "\\{?\\\\'\\{?o\\}?\\}?" => "ó", + "\\{?\\\\\\^\\{?o\\}?\\}?" => "ô", + "\\{?\\\\~\\{?o\\}?\\}?" => "õ", + "\\{?\\\\\"\\{?o\\}?\\}?" => "ö", + "\\{?\\\\textdiv\\}?" => "÷", + "\\{?\\\\o\\}?" => "ø", + "\\{?\\\\`\\{?u\\}?\\}?" => "ù", + "\\{?\\\\'\\{?u\\}?\\}?" => "ú", + "\\{?\\\\\\^\\{?u\\}?\\}?" => "û", + "\\{?\\\\\"\\{?u\\}?\\}?" => "ü", + "\\{?\\\\'\\{?y\\}?\\}?" => "ý", + "\\{?\\\\th\\}?" => "þ", + "\\{?\\\\\"\\{?y\\}?\\}?" => "ÿ", + "\\{?\\\\u\\{?A\\}?\\}?" => "Ă", + "\\{?\\\\u\\{?a\\}?\\}?" => "ă", + "\\{?\\\\k\\{?a\\}?\\}?" => "ą", + "\\{?\\\\'\\{?C\\}?\\}?" => "Ć", + "\\{?\\\\'\\{?c\\}?\\}?" => "ć", + "\\{?\\\\v\\{?C\\}?\\}?" => "Č", + "\\{?\\\\v\\{?c\\}?\\}?" => "č", + "\\{?\\\\v\\{?D\\}?\\}?" => "Ď", + "\\{?\\\\v\\{?d\\}?\\}?" => "ď", + "\\{?\\\\DJ\\}?" => "Đ", + "\\{?\\\\dj\\}?" => "đ", + "\\{?\\\\k\\{?E\\}?\\}?" => "Ę", + "\\{?\\\\k\\{?e\\}?\\}?" => "ę", + "\\{?\\\\v\\{?E\\}?\\}?" => "Ě", + "\\{?\\\\v\\{?e\\}?\\}?" => "ě", + "\\{?\\\\u\s?\\{?e\\}?\\}?" => "ĕ", + "\\{?\\\\u\\{?G\\}?\\}?" => "Ğ", + "\\{?\\\\u\\{?g\\}?\\}?" => "ğ", + "\\{?\\\\.\\{?g\\}?\\}?" => "ġ", + "\\{?\\\\.\\{?I\\}?\\}?" => "İ", + "\\{?\\\\i\\}?" => "ı", + "\\{?\\\\'\\{?L\\}?\\}?" => "Ĺ", + "\\{?\\\\v\\{?L\\}?\\}?" => "Ľ", + "\\{?\\\\v\\{?l\\}?\\}?" => "ľ", + "\\{?\\\\L\\}?" => "Ł", + "\\{?\\\\l\\}?" => "ł", + "\\{?\\\\'\\{?N\\}?\\}?" => "Ń", + "\\{?\\\\'\\{?n\\}?\\}?" => "ń", + "\\{?\\\\v\\{?N\\}?\\}?" => "Ň", + "\\{?\\\\v\\{?n\\}?\\}?" => "ň", + "\\{?\\\\NG\\}?" => "Ŋ", + "\\{?\\\\ng\\}?" => "ŋ", + "\\{?\\\\H\\{?O\\}?\\}?" => "Ő", + "\\{?\\\\H\\{?o\\}?\\}?" => "ő", + "\\{?\\\\OE\\}?" => "Œ", + "\\{?\\\\oe\\}?" => "œ", + "\\{?\\\\'\\{?R\\}?\\}?" => "Ŕ", + "\\{?\\\\'\\{?r\\}?\\}?" => "ŕ", + "\\{?\\\\v\\{?R\\}?\\}?" => "Ř", + "\\{?\\\\v\\{?r\\}?\\}?" => "ř", + "\\{?\\\\'\\{?S\\}?\\}?" => "Ś", + "\\{?\\\\'\\{?s\\}?\\}?" => "ś", + "\\{?\\\\c\\{?S\\}?\\}?" => "Ş", + "\\{?\\\\c\\{?s\\}?\\}?" => "ş", + "\\{?\\\\v\\{?S\\}?\\}?" => "Š", + "\\{?\\\\v\\{?s\\}?\\}?" => "š", + "\\{?\\\\c\\{?T\\}?\\}?" => "Ţ", + "\\{?\\\\c\\{?t\\}?\\}?" => "ţ", + "\\{?\\\\v\\{?T\\}?\\}?" => "Ť", + "\\{?\\\\v\\{?t\\}?\\}?" => "ť", + "\\{?\\\\r\\{?U\\}?\\}?" => "Ů", + "\\{?\\\\r\\{?u\\}?\\}?" => "ů", + "\\{?\\\\H\\{?U\\}?\\}?" => "Ű", + "\\{?\\\\H\\{?u\\}?\\}?" => "ű", + "\\{?\\\\\"\\{?Y\\}?\\}?" => "Ÿ", + "\\{?\\\\'\\{?Z\\}?\\}?" => "Ź", + "\\{?\\\\'\\{?z\\}?\\}?" => "ź", + "\\{?\\\\.\\{?Z\\}?\\}?" => "Ż", + "\\{?\\\\.\\{?z\\}?\\}?" => "ż", + "\\{?\\\\v\\{?Z\\}?\\}?" => "Ž", + "\\{?\\\\v\\{?z\\}?\\}?" => "ž", + "\\{?\\\\textflorin\\}?" => "ƒ", + "\\{?\\\\textasciicircum\\}?" => "ˆ", + "\\{?\\\\textacutedbl\\}?" => "˝", + "\\{?\\\\textendash\\}?|--" => "–", + "\\{?\\\\textemdash\\}?|---" => "—", + "\\{?\\\\textbardbl\\}?" => "‖", + "\\{?\\\\textunderscore\\}?" => "‗", + "\\{?\\\\textquoteleft\\}?" => "‘", + "\\{?\\\\textquoteright\\}?" => "’", + "\\{?\\\\quotesinglbase\\}?" => "‚", + "\\{?\\\\textquotedblleft\\}?" => "“", + "\\{?\\\\textquotedblright\\}?" => "”", + "\\{?\\\\quotedblbase\\}?" => "„", + "\\{?\\\\textdagger\\}?" => "†", + "\\{?\\\\textdaggerdbl\\}?" => "‡", + "\\{?\\\\textbullet\\}?" => "•", + "\\{?\\\\textellipsis\\}?" => "…", + "\\{?\\\\textperthousand\\}?" => "‰", + "\\{?\\\\guilsinglleft\\}?" => "‹", + "\\{?\\\\guilsinglright\\}?" => "›", + "\\{?\\\\textfractionsolidus\\}?" => "⁄", + '\\$\\^\\{0\\}\\$' => "⁰", + '\\$\\^\\{4\\}\\$' => "⁴", + '\\$\\^\\{5\\}\\$' => "⁵", + '\\$\\^\\{6\\}\\$' => "⁶", + '\\$\\^\\{7\\}\\$' => "⁷", + '\\$\\^\\{8\\}\\$' => "⁸", + '\\$\\^\\{9\\}\\$' => "⁹", + '\\$\\^\\{+\\}\\$' => "⁺", + '\\$\\^\\{-\\}\\$' => "⁻", + '\\$\\^\\{=\\}\\$' => "⁼", + '\\$\\^\\{n\\}\\$' => "ⁿ", + '\\$_\\{0\\}\\$' => "₀", + '\\$_\\{1\\}\\$' => "₁", + '\\$_\\{2\\}\\$' => "₂", + '\\$_\\{3\\}\\$' => "₃", + '\\$_\\{4\\}\\$' => "₄", + '\\$_\\{5\\}\\$' => "₅", + '\\$_\\{6\\}\\$' => "₆", + '\\$_\\{7\\}\\$' => "₇", + '\\$_\\{8\\}\\$' => "₈", + '\\$_\\{9\\}\\$' => "₉", + '\\$_\\{+\\}\\$' => "₊", + '\\$_\\{-\\}\\$' => "₋", + '\\$_\\{=\\}\\$' => "₌", + "\\{?\\\\texteuro\\}?" => "€", + "\\{?\\\\textcelsius\\}?" => "℃", + "\\{?\\\\textnumero\\}?" => "№", + "\\{?\\\\textcircledP\\}?" => "℗", + "\\{?\\\\textservicemark\\}?" => "℠", + "\\{?\\\\texttrademark\\}?" => "™", + "\\{?\\\\textohm\\}?" => "Ω", + "\\{?\\\\textestimated\\}?" => "℮", + "\\{?\\\\textleftarrow\\}?" => "←", + "\\{?\\\\textuparrow\\}?" => "↑", + "\\{?\\\\textrightarrow\\}?" => "→", + "\\{?\\\\textdownarrow\\}?" => "↓", + '\\$\\\\infty\\$' => "∞", + "\\{?\\\\textlangle\\}?" => "〈", + "\\{?\\\\textrangle\\}?" => "〉", + "\\{?\\\\textvisiblespace\\}?" => "␣", + "\\{?\\\\textopenbullet\\}?" => "◦", + "\\{?\\\\Delta\\}?" => "Δ", + "\\{?\\\\iota\\}?" => "ι", + "\\{?\\\\omicron\\}?" => "ο", + "\\{?\\\\mu\\}?" => "μ", + "\\{?\\\\eta\\}?" => "η", + "\\{?\\\\delta\\}?" => "δ", + "\\{?\\\\varsigma\\}?" => "ς", + "\\{?\\\\Sigma\\}?" => "Σ", + "\\{?\\\\pi\\}?" => "π", + "\\{?\\\\nu\\}?" => "ν", + "\\{?\\\\epsilon\\}?" => "ε", + "\\{?\\\\lambda\\}?" => "λ", + "\\{?\\\\=\\{?o\\}?\\}?" => "ō", + ]; + + /** + * Returns search patterns. + * + * @return array + * Search pattern strings. + */ + public function getSearchPatterns() { + $searchStrings = array_keys(self::LATEX_UNICODE); + foreach ($searchStrings as $key => $value) { + // Add search pattern delimiters. + $searchStrings[$key] = "/" . $value . "/"; + } + return $searchStrings; + } + + /** + * Returns replacement strings. + * + * @return array + * Replacement strings. + */ + public function getReplaceStrings() { + return array_values(self::LATEX_UNICODE); + } + +} diff --git a/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php b/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php index fd845978be7..73bf5e21ee2 100644 --- a/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php +++ b/profile/modules/cp/modules/cp_import/src/Helper/CpImportPublicationHelper.php @@ -3,12 +3,15 @@ namespace Drupal\cp_import\Helper; use Drupal\bibcite\Plugin\BibciteFormatManager; +use Drupal\bibcite_entity\Entity\Contributor; use Drupal\bibcite_entity\Entity\Reference; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityTypeManager; +use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Logger\LoggerChannelFactory; use Drupal\vsite\Plugin\VsiteContextManager; use Symfony\Component\Serializer\Serializer; +use Drupal\cp_import\CpImportLatexUnicodeMapping; /** * Class CpImportPublicationHelper. @@ -81,6 +84,7 @@ public function __construct(VsiteContextManager $vsiteContextManager, EntityType * For use in batch contexts. * * @throws \Drupal\Component\Plugin\Exception\PluginException + * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException */ public function savePublicationEntity(array $entry, $formatId): array { $result = []; @@ -101,9 +105,22 @@ public function savePublicationEntity(array $entry, $formatId): array { } } + // Map special characters. + $this->mapSpecialChars($entry); + /** @var \Drupal\bibcite_entity\Entity\Reference $entity */ try { $entity = $this->serializer->denormalize($entry, Reference::class, $format->getPluginId(), $denormalize_context); + // Handle Editors. + if (isset($entry['editor']) && $editors = $entry['editor']) { + $authorField = $entity->get('author'); + $this->saveEditors($editors, $authorField, $format, $denormalize_context); + } + // Handle url as we need to map it to custom field. + if (isset($entry['url']) && $url = $entry['url']) { + $publishersVersionField = $entity->get('publishers_version'); + $this->savePublishersVersionUrl($url, $publishersVersionField); + } } catch (\UnexpectedValueException $e) { // Skip import for this row. @@ -151,4 +168,67 @@ public function mapPublicationHtmlFields(Reference $entity): void { $entity->save(); } + /** + * Maps special characters from bibtex(others) to publication. + * + * @param array $entry + * The decoded entry array. + */ + public function mapSpecialChars(array &$entry): void { + // Handle special chars. + $cpImportMappingObj = new CpImportLatexUnicodeMapping(); + $searchStrings = $cpImportMappingObj->getSearchPatterns(); + $replaceStrings = $cpImportMappingObj->getReplaceStrings(); + foreach ($entry as $key => $item) { + // Generally Author and Editor keys will be arrays so we can skip them. + if (!is_array($item)) { + $entry[$key] = preg_replace($searchStrings, $replaceStrings, $item); + } + } + } + + /** + * Handle Editors as they are disregarded currently by contrib module. + * + * @param string $editors + * The editors string. + * @param \Drupal\Core\Field\FieldItemListInterface $authorField + * The field to save editors to. + * @param string $format + * The format to use such as bibtex and pubmed. + * @param array $context + * Settings to be used for the process. + */ + public function saveEditors($editors, FieldItemListInterface $authorField, $format, array $context): void { + $editors = explode(' and ', $editors); + foreach ($editors as $editor) { + $denormalizedEditor = $this->serializer->denormalize(['name' => [['value' => $editor]]], Contributor::class, $format, $context); + // Save editor as contributor entity with proper role and category. + $denormalizedEditor->save(); + $authorField->appendItem([ + 'target_id' => $denormalizedEditor->id(), + 'category' => 'primary', + 'role' => 'editor', + ]); + } + } + + /** + * Save the url to our custom publisher's version field. + * + * @param string $url + * The url to save. + * @param \Drupal\Core\Field\FieldItemListInterface $publishersVersionField + * The field to save url to. + * + * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException + */ + public function savePublishersVersionUrl($url, FieldItemListInterface $publishersVersionField) { + $publishersVersionField->setValue([ + 'title' => $this->t("Publisher's Version"), + 'uri' => $url, + 'options' => [], + ]); + } + } diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php index 01e5f2330cb..e86dfd6a617 100644 --- a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportPublicationsTest.php @@ -17,7 +17,7 @@ class CpImportPublicationsTest extends OsExistingSiteTestBase { /** * CpImport helper service. * - * @var \Drupal\cp_import\Helper\CpImportHelper + * @var \Drupal\cp_import\Helper\CpImportPublicationHelper */ protected $cpImportHelper; @@ -134,6 +134,86 @@ public function testCpImportHelperSavePublicationBibtexCodedYear() { $this->assertEquals(10030, $pubEntity->get('bibcite_year')->getValue()[0]['value']); } + /** + * Tests Special character mapping works. + * + * @covers ::mapSpecialChars + */ + public function testCpImportHelperMapSpecialChars() { + + $entry = [ + // Test some random symbols. + 'symbols' => '$\#$ \%\ \&\  + - ( )\  * \& ^ \%$ $\#$ @ !\ \  {\~A}', + // Test some random text and symbol combination. + 'texts' => '{\textyen} {\~A} {\textregistered} "paper" {\textquoteright}presents{\textquoteright} {\textquoteleft}measurements{\textquoteleft}', + ]; + + //   appearing is ok as it will be read and handled by the browser not + // our mapper. + $expectedSymbols = '# % &  + - ( )  * & ^ %$ # @ !   Ã'; + $expectedTextSymbols = '¥ à ® "paper" ’presents’ ‘measurements‘'; + + $this->cpImportHelper->mapSpecialChars($entry); + + $this->assertEquals($expectedSymbols, $entry['symbols']); + $this->assertEquals($expectedTextSymbols, $entry['texts']); + } + + /** + * Tests Editors are saved correctly and url mapping. + * + * @covers ::saveEditors + * @covers ::savePublishersVersionUrl + */ + public function testCpImportHelperSaveEditors() { + + $storage = $this->entityTypeManager->getStorage('bibcite_reference'); + $title = $this->randomString(); + // Prepare data entry array. + $abstract = 'This paper presents measurements of spectrally'; + $entry = [ + 'type' => 'article', + 'journal' => 'Proceeding of the Combustion Institute', + 'title' => $title, + 'volume' => '32', + 'year' => '2009', + 'pages' => '963-970', + 'chapter' => '963', + 'url' => 'http://abcde.net/thisarticle', + 'abstract' => $abstract, + 'author' => ['F. Goulay', 'L. Nemes'], + // Editor not processed by the decoder so they will + // be passed as a string for further processing. + 'editor' => 'Editor One and Editor Two', + ]; + + $context = $this->cpImportHelper->savePublicationEntity($entry, 'bibtex'); + + $pubArr = $storage->loadByProperties([ + 'type' => 'journal_article', + 'title' => $title, + ]); + + // Assert Saving Bibtex entry with editors worked. + $this->assertNotEmpty($pubArr); + $this->assertArrayHasKey('success', $context); + /** @var \Drupal\bibcite_entity\Entity\Reference $pubEntity */ + $pubEntity = array_values($pubArr)[0]; + $this->markEntityForCleanup($pubEntity); + // Assert values. + $this->assertEquals($title, $pubEntity->get('title')->getValue()[0]['value']); + // Test editors are saved correctly. + $contributors = $pubEntity->get('author')->getValue(); + $this->assertCount(4, $contributors); + $this->assertEquals('editor', $contributors[2]['role']); + $this->assertEquals('primary', $contributors[3]['category']); + + // Test url is saved correctly. + $urlField = $pubEntity->get('publishers_version')->getValue()[0]; + $this->assertNotEmpty($urlField['title']); + $this->assertEquals('http://abcde.net/thisarticle', $urlField['uri']); + } + /** * Tests Saving a Pubmed entry works. * @@ -141,7 +221,9 @@ public function testCpImportHelperSavePublicationBibtexCodedYear() { * @covers ::mapPublicationHtmlFields * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException */ public function testCpImportHelperSavePublicationPubmedXml() { From 579431043254914216fea52197e4deaaf11d8d82 Mon Sep 17 00:00:00 2001 From: Saurabh Pandit <58168562+saurabh-axl@users.noreply.github.com> Date: Fri, 28 Feb 2020 18:26:02 +0530 Subject: [PATCH 15/58] Issue #12844 - Import News (#13065) * Issue #12844 - Added Import template and migrate yaml for news * Issue #12844 - Added Import News migration and validation logic * Issue #12844 - Test cases for Import News * Issue #12844 - Code cleanup * Issue #12844 - CSV encoding issue * Issue #12844 - Travis test fix * Issue #12844 - PR Review Correction Co-authored-by: Richard Brandon --- composer.json | 1 + composer.lock | 113 ++++++--- config/sync/core.extension.yml | 1 + .../os_news/migrations/os_news_import.yml | 40 +++ .../apps/os_news/src/Plugin/App/NewsApp.php | 74 +++++- .../cp_import/import_templates/os_news.csv | 2 + .../AppImport/os_news_import/AppImport.php | 238 ++++++++++++++++++ .../cp_import_csv_test/artifacts/news.csv | 7 + .../artifacts/news_small.csv | 5 + .../src/ExistingSite/CpImportNewsTest.php | 226 +++++++++++++++++ 10 files changed, 669 insertions(+), 38 deletions(-) create mode 100644 profile/modules/apps/os_news/migrations/os_news_import.yml create mode 100644 profile/modules/cp/modules/cp_import/import_templates/os_news.csv create mode 100644 profile/modules/cp/modules/cp_import/src/AppImport/os_news_import/AppImport.php create mode 100644 profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news.csv create mode 100644 profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news_small.csv create mode 100644 profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportNewsTest.php diff --git a/composer.json b/composer.json index d029a488eea..0baa7861fde 100644 --- a/composer.json +++ b/composer.json @@ -208,6 +208,7 @@ "drupal/mailchimp": "^1.8", "drupal/mathjax": "^2.7", "drupal/metatag": "^1.7", + "drupal/migrate_file": "^1.1", "drupal/migrate_source_csv": "^3.1", "drupal/migrate_tools": "^4.5", "drupal/node_revision_delete": "^1.0@beta", diff --git a/composer.lock b/composer.lock index a30cfdc5326..9d819a61b5e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "47da57be3681f7267ca3a866d29ab984", + "content-hash": "de50866308c4b1d37c2547413dee3192", "packages": [ { "name": "academicpuma/citeproc-php", @@ -297,9 +297,9 @@ "authors": [ { "name": "Nils Werner", + "role": "Developer", "email": "nils.werner@audiolabs-erlangen.de", - "homepage": "http://www.audiolabs-erlangen.de", - "role": "Developer" + "homepage": "http://www.audiolabs-erlangen.de" } ], "description": "Bibtex parser for PHP 5.3", @@ -5592,10 +5592,6 @@ "GPL-2.0-or-later" ], "authors": [ - { - "name": "Berdir", - "homepage": "https://www.drupal.org/user/214652" - }, { "name": "Frans", "homepage": "https://www.drupal.org/user/514222" @@ -5612,7 +5608,7 @@ "description": "Adds a Entity Reference field type with revision support.", "homepage": "https://www.drupal.org/project/entity_reference_revisions", "support": { - "source": "https://git.drupalcode.org/project/entity_reference_revisions" + "source": "http://cgit.drupalcode.org/entity_reference_revisions" } }, { @@ -5847,8 +5843,8 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0-alpha2+72-dev", - "datestamp": "1526651284", + "version": "8.x-1.0-alpha2+94-dev", + "datestamp": "1528091885", "security-coverage": { "status": "not-covered", "message": "Dev releases are not covered by Drupal security advisories." @@ -5878,6 +5874,10 @@ { "name": "tim.plunkett", "homepage": "https://www.drupal.org/user/241634" + }, + { + "name": "tstoeckler", + "homepage": "https://www.drupal.org/user/107158" } ], "description": "Integrates the Fullcalender Library from https://fullcalendar.io", @@ -6376,18 +6376,10 @@ "name": "amyvs", "homepage": "https://www.drupal.org/user/3181721" }, - { - "name": "aprice42", - "homepage": "https://www.drupal.org/user/369147" - }, { "name": "gcb", "homepage": "https://www.drupal.org/user/1682976" }, - { - "name": "julia.leah.ford", - "homepage": "https://www.drupal.org/user/3590443" - }, { "name": "levelos", "homepage": "https://www.drupal.org/user/54135" @@ -6420,7 +6412,7 @@ "description": "Mailchimp is an integration with the Mailchimp Mass email tool.", "homepage": "http://drupal.org/project/mailchimp", "support": { - "source": "https://git.drupalcode.org/project/mailchimp" + "source": "http://cgit.drupalcode.org/mailchimp" } }, { @@ -6542,6 +6534,57 @@ "issues": "http://drupal.org/project/issues/metatag" } }, + { + "name": "drupal/migrate_file", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/migrate_file.git", + "reference": "8.x-1.1" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/migrate_file-8.x-1.1.zip", + "reference": "8.x-1.1", + "shasum": "4a24edc577541b5aa67682a4f89c8dfd7c0788d5" + }, + "require": { + "drupal/core": "*" + }, + "type": "drupal-module", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + }, + "drupal": { + "version": "8.x-1.1", + "datestamp": "1539064380", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "drclaw", + "homepage": "https://www.drupal.org/user/823702" + } + ], + "description": "Additional support for migrating files including downloading remote files and using remote uris (without download)", + "homepage": "https://www.drupal.org/project/migrate_file", + "keywords": [ + "Drupal" + ], + "support": { + "source": "http://cgit.drupalcode.org/migrate_file", + "issues": "https://www.drupal.org/project/issues/migrate_file" + } + }, { "name": "drupal/migrate_plus", "version": "4.2.0", @@ -6994,10 +7037,6 @@ "name": "jeroen.b", "homepage": "https://www.drupal.org/user/1853532" }, - { - "name": "jstoller", - "homepage": "https://www.drupal.org/user/99012" - }, { "name": "miro_dietiker", "homepage": "https://www.drupal.org/user/227761" @@ -7152,7 +7191,7 @@ "description": "Allows users to redirect from old URLs to new URLs.", "homepage": "https://www.drupal.org/project/redirect", "support": { - "source": "https://git.drupalcode.org/project/redirect" + "source": "http://cgit.drupalcode.org/redirect" } }, { @@ -8526,7 +8565,7 @@ "description": "Provides an accordion views display plugin.", "homepage": "https://www.drupal.org/project/views_accordion", "support": { - "source": "https://git.drupalcode.org/project/views_accordion", + "source": "http://cgit.drupalcode.org/views_accordion", "issues": "https://www.drupal.org/project/issues/views_accordion" } }, @@ -8574,7 +8613,7 @@ "description": "Provides advanced route customisation for Views.", "homepage": "https://www.drupal.org/project/views_advanced_routing", "support": { - "source": "https://git.drupalcode.org/project/views_advanced_routing" + "source": "http://cgit.drupalcode.org/views_advanced_routing" } }, { @@ -8640,10 +8679,6 @@ "GPL-2.0-or-later" ], "authors": [ - { - "name": "Bobík", - "homepage": "https://www.drupal.org/user/123612" - }, { "name": "Remon", "homepage": "https://www.drupal.org/user/143827" @@ -8656,7 +8691,7 @@ "description": "A pager which allows an infinite scroll effect for views.", "homepage": "https://www.drupal.org/project/views_infinite_scroll", "support": { - "source": "https://git.drupalcode.org/project/views_infinite_scroll" + "source": "http://cgit.drupalcode.org/views_infinite_scroll" } }, { @@ -10325,8 +10360,8 @@ "authors": [ { "name": "Frank Kleine", - "homepage": "http://frankkleine.de/", - "role": "Developer" + "role": "Developer", + "homepage": "http://frankkleine.de/" } ], "description": "Virtual file system to mock the real file system in unit tests.", @@ -10824,8 +10859,8 @@ "authors": [ { "name": "Christian Weiske", - "email": "cweiske@php.net", - "role": "Lead" + "role": "Lead", + "email": "cweiske@php.net" } ], "description": "Minimal set of PEAR core files to be used as composer dependency", @@ -14904,8 +14939,8 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", @@ -16221,6 +16256,10 @@ "name": "cs_shadow", "homepage": "https://www.drupal.org/user/2828287" }, + { + "name": "oknate", + "homepage": "https://www.drupal.org/user/471638" + }, { "name": "phenaproxima", "homepage": "https://www.drupal.org/user/205645" diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index af0a730bc11..910e390acef 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -101,6 +101,7 @@ module: metatag_twitter_cards: 0 metatag_views: 0 migrate: 0 + migrate_file: 0 migrate_plus: 0 migrate_source_csv: 0 migrate_tools: 0 diff --git a/profile/modules/apps/os_news/migrations/os_news_import.yml b/profile/modules/apps/os_news/migrations/os_news_import.yml new file mode 100644 index 00000000000..e562611e9fc --- /dev/null +++ b/profile/modules/apps/os_news/migrations/os_news_import.yml @@ -0,0 +1,40 @@ +id: os_news_import +migration_tags: + - CSV +label: 'Os News CSV Migration' +source: + plugin: csv + path: public://importcsv/os_news.csv + ids: [Timestamp, Title, Date] + constants: + view: '/news/' +process: + type: + plugin: default_value + default_value: news + title: Title + body: Body + created: + plugin: format_date + from_format: Y-m-d + to_format: U + source: Created date + field_date: Date + field_redirect_to_source: Redirect + field_photo: + plugin: image_import + source: Image + field_attached_media/target_id: Files + path/pathauto: + plugin: default_value + default_value: 0 # Disable pathauto + path/alias: + plugin: concat + source: + - constants/view + - Path +destination: + plugin: 'entity:node' +migration_dependencies: + required: { } + optional: { } diff --git a/profile/modules/apps/os_news/src/Plugin/App/NewsApp.php b/profile/modules/apps/os_news/src/Plugin/App/NewsApp.php index 9fd8b6f443e..8f11e1a9ccd 100644 --- a/profile/modules/apps/os_news/src/Plugin/App/NewsApp.php +++ b/profile/modules/apps/os_news/src/Plugin/App/NewsApp.php @@ -2,7 +2,14 @@ namespace Drupal\os_news\Plugin\App; +use Drupal\Core\Entity\EntityTypeManager; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Drupal\cp_import\AppImportFactory; +use Drupal\cp_import\Helper\CpImportHelper; +use Drupal\migrate\Plugin\MigrationPluginManager; use Drupal\vsite\Plugin\AppPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * News app. @@ -21,9 +28,74 @@ * }, * }, * id = "news", - * contextualRoute = "view.news.page_1" + * contextualRoute = "view.news.page_1", + * cpImportId = "os_news_import", + * cpImportFilePath = "public://importcsv/os_news.csv" * ) */ class NewsApp extends AppPluginBase { + /** + * App Import factory service. + * + * @var \Drupal\cp_import\AppImportFactory + */ + protected $appImportFactory; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationPluginManager $migrationPluginManager, CpImportHelper $cpImportHelper, Messenger $messenger, EntityTypeManager $entityTypeManager, AppImportFactory $appImportFactory) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migrationPluginManager, $cpImportHelper, $messenger, $entityTypeManager); + $this->appImportFactory = $appImportFactory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.migration'), + $container->get('cp_import.helper'), + $container->get('messenger'), + $container->get('entity_type.manager'), + $container->get('app_import_factory') + ); + } + + /** + * Validates import file and shows errors row wise. + * + * @param array $form + * The form. + * @param \Drupal\Core\Form\FormStateInterface $formState + * The Form State. + */ + public function validateImportSource(array $form, FormStateInterface $formState) { + $data = parent::validateImportSource($form, $formState); + if (!$data) { + return; + } + + $definition = $this->getPluginDefinition(); + $faqImport = $this->appImportFactory->create($definition['cpImportId']); + + // Validate Headers. + if ($missing = $faqImport->validateHeaders($data)) { + $headerMessage = $this->t('The following Header/columns are missing:
    @Title @Date @Body @Redirect @Image @Files @Created date @Path

The structure of your CSV file probably needs to be updated. Please download the template again.', $missing); + $this->messenger->addError($headerMessage); + $formState->setError($form['import_file']); + return; + } + + // Validate rows. + if ($message = $faqImport->validateRows($data)) { + $formState->setError($form['import_file']); + $this->messenger->addError($this->t('@title @news_date @image @file @date', $message)); + } + } + } diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_news.csv b/profile/modules/cp/modules/cp_import/import_templates/os_news.csv new file mode 100644 index 00000000000..a3665ed6d19 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/import_templates/os_news.csv @@ -0,0 +1,2 @@ +Title,Date,Body,Redirect,Image,Files,Created date,Path +This is the news title,2020-11-30,Text,,https://hwpi.harvard.edu/files/torman_fileserver/files/alberta.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,news-path diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_news_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_news_import/AppImport.php new file mode 100644 index 00000000000..c792f639128 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_news_import/AppImport.php @@ -0,0 +1,238 @@ +getRow(); + $dest_val = $row->getDestination(); + $media_val = $dest_val['field_attached_media']['target_id']; + // If not a valid url return and don't do anything , this reduces the risk + // of malicious scripts as we do not want to support HTML media from here. + if (UrlHelper::isValid($media_val)) { + // Get the media. + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type); + if ($media_entity) { + $row->setDestinationProperty('field_attached_media/target_id', $media_entity->id()); + } + } + } + + /** + * {@inheritdoc} + */ + public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { + $ids = $event->getDestinationIdValues(); + foreach ($ids as $id) { + $this->cpImportHelper->addContentToVsite($id, $this->groupPluginId, 'node'); + } + parent::migratePostRowSaveActions($event); + } + + /** + * {@inheritdoc} + */ + public function prepareRowActions(MigratePrepareRowEvent $event) { + $source = $event->getRow()->getSource(); + $createdDate = $source['Created date']; + if ($createdDate) { + $date = DateTime::createFromFormat('Y-m-d', $createdDate); + if ($date->format('Y-n-j') == $createdDate) { + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } + } + else { + $date = new DateTime(); + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } + + $news_date = $source['Date']; + if ($news_date) { + $date = DateTime::createFromFormat('Y-m-d', $news_date); + if ($date->format('Y-n-j') == $news_date) { + $event->getRow()->setSourceProperty('Date', $date->format('Y-m-d')); + } + } + else { + $date = new DateTime(); + $event->getRow()->setSourceProperty('Date', $date->format('Y-m-d')); + } + parent::prepareRowActions($event); + } + + /** + * Validates headers from csv file array. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateHeaders(array $data): array { + $headerMissing = FALSE; + $newsHeaders = [ + 'Title', + 'Date', + 'Body', + 'Redirect', + 'Image', + 'Files', + 'Created date', + 'Path', + ]; + $missing = [ + '@Title' => '', + '@Date' => '', + '@Body' => '', + '@Redirect' => '', + '@Image' => '', + '@Files' => '', + '@Created date' => '', + '@Path' => '', + ]; + + foreach ($data as $row) { + $columnHeaders = array_keys($row); + foreach ($newsHeaders as $newsHeader) { + if (!in_array($newsHeader, $columnHeaders)) { + $missing['@' . $newsHeader] = $this->t('
  • @column
  • ', ['@column' => $newsHeader]); + $headerMissing = TRUE; + } + } + } + return $headerMissing ? $missing : []; + } + + /** + * Validates Rows for News csv import. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateRows(array $data) : array { + $hasError = FALSE; + $titleRows = ''; + $bodyRows = ''; + $fileRows = ''; + $dateRows = ''; + $newsDateRows = ''; + $imageRows = ''; + $emptyDateRows = ''; + $message = [ + '@title' => '', + '@news_date' => '', + '@file' => '', + '@date' => '', + '@image' => '', + ]; + + foreach ($data as $delta => $row) { + $row_number = ++$delta; + // Validate Title. + if (!$row['Title']) { + $titleRows .= $row_number . ','; + } + // Validate Date. + if ($news_date = $row['Date']) { + $date = DateTime::createFromFormat('Y-m-d', $news_date); + if (!$date || !($date->format('Y-m-d') == $news_date || $date->format('Y-n-j') == $news_date)) { + $newsDateRows .= $row_number . ','; + } + } + else { + $emptyDateRows .= $row_number . ','; + } + // Validate Body. + if (!$row['Body']) { + $bodyRows .= $row_number . ','; + } + // Validate Image url. + if ($url = $row['Image']) { + $headers = get_headers($url, 1); + if (strpos($headers[0], '200') === FALSE) { + $imageRows .= $row_number . ','; + } + } + // Validate File url. + if ($url = $row['Files']) { + $headers = get_headers($url, 1); + if (strpos($headers[0], '200') === FALSE) { + $fileRows .= $row_number . ','; + } + } + // Validate Created Date. + if ($createdDate = $row['Created date']) { + $date = DateTime::createFromFormat('Y-m-d', $createdDate); + if (!$date || !($date->format('Y-m-d') == $createdDate || $date->format('Y-n-j') == $createdDate)) { + $dateRows .= $row_number . ','; + } + } + } + $titleRows = rtrim($titleRows, ','); + if ($titleRows) { + $message['@title'] = $this->t('Title is required for row/rows @titleRows
    ', ['@titleRows' => $titleRows]); + $hasError = TRUE; + } + $newsDateRows = rtrim($newsDateRows, ','); + if ($newsDateRows) { + $message['@news_date'] = $this->t('Date/Date Format is invalid for row/rows @newsDateRows
    ', ['@newsDateRows' => $newsDateRows]); + $hasError = TRUE; + } + $emptyDateRows = rtrim($emptyDateRows, ','); + if ($emptyDateRows) { + $message['@news_date'] = $this->t('Date is empty for row/rows @emptyDateRows
    ', ['@emptyDateRows' => $emptyDateRows]); + $hasError = TRUE; + } + $imageRows = rtrim($imageRows, ','); + if ($imageRows) { + $message['@image'] = $this->t('Image url is invalid for row/rows @imageRows
    ', ['@imageRows' => $imageRows]); + $hasError = TRUE; + } + $fileRows = rtrim($fileRows, ','); + if ($fileRows) { + $message['@file'] = $this->t('File url is invalid for row/rows @fileRows
    ', ['@fileRows' => $fileRows]); + $hasError = TRUE; + } + $dateRows = rtrim($dateRows, ','); + if ($dateRows) { + $message['@date'] = $this->t('Date/Date Format is invalid for row/rows @dateRows
    ', ['@dateRows' => $dateRows]); + $hasError = TRUE; + } + return $hasError ? $message : []; + } + +} diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news.csv new file mode 100644 index 00000000000..77ac112de47 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news.csv @@ -0,0 +1,7 @@ +Title,Date,Body,Redirect,Image,Files,Created date,Path +Os Title1,2020-02-18,Text Body,https://scholar.harvard.edu/bilsi/,https://scholar.harvard.edu/files/bilsi/files/beach-breeze-daylight-1903707_01_0.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-1 +Os Title2,2020-02-18,Text Body,,https://scholar.harvard.edu/files/bilsi/files/samplejpgimage_100kbmb_0.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-2 +Os Title3,2020-02-18,Text Body,https://scholar.harvard.edu/bilsi/,https://scholar.harvard.edu/files/bilsi/files/architecture-buildings-city-569780.jpg?m=1566895594,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-3 +Os Title4,2020-02-18,Text Body,,https://scholar.harvard.edu/files/bilsi/files/stil-1487686-unsplash.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-4 +Os Title5,2020-02-18,Text Body,,,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-5 +Os Title6,2020-02-18,Text Body,https://scholar.harvard.edu/bilsi/,https://scholar.harvard.edu/files/bilsi/files/beach-breeze-daylight-1903707_01_0.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-6 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news_small.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news_small.csv new file mode 100644 index 00000000000..867226457a2 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/news_small.csv @@ -0,0 +1,5 @@ +Title,Date,Body,Redirect,Image,Files,Created date,Path +Os Title1,2020-02-20,Text Body,https://scholar.harvard.edu/bilsi/,https://scholar.harvard.edu/files/bilsi/files/beach-breeze-daylight-1903707_01_0.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-1 +Os Title7,2020-02-21,Text Body,,https://scholar.harvard.edu/files/bilsi/files/samplejpgimage_100kbmb_0.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-7 +Os Title8,2020-02-22,Text Body,https://scholar.harvard.edu/bilsi/,https://scholar.harvard.edu/files/bilsi/files/architecture-buildings-city-569780.jpg?m=1566895594,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-8 +Os Title9,2020-02-23,Text Body,,https://scholar.harvard.edu/files/bilsi/files/stil-1487686-unsplash.jpg,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-12-31,os-news-9 diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportNewsTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportNewsTest.php new file mode 100644 index 00000000000..0be1898338a --- /dev/null +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportNewsTest.php @@ -0,0 +1,226 @@ +vsiteContextManager->activateVsite($this->group); + $this->cpImportHelper = $this->container->get('cp_import.helper'); + $this->migrationManager = $this->container->get('plugin.manager.migration'); + $this->entityTypeManager = $this->container->get('entity_type.manager'); + $this->fileSystem = $this->container->get('file_system'); + $this->groupMember = $this->createUser(); + $this->group->addMember($this->groupMember); + $this->drupalLogin($this->groupMember); + } + + /** + * Tests CpImport News AppImport factory. + */ + public function testCpImportNewsAppImportFactory() { + /** @var \Drupal\cp_import\AppImportFactory $appImportFactory */ + $appImportFactory = $this->container->get('app_import_factory'); + $instance = $appImportFactory->create('os_news_import'); + $this->assertInstanceOf(AppImport::class, $instance); + } + + /** + * Tests CpImport News header validations. + */ + public function testCpImportNewsHeaderValidation() { + /** @var \Drupal\cp_import\AppImportFactory $appImportFactory */ + $appImportFactory = $this->container->get('app_import_factory'); + $instance = $appImportFactory->create('os_news_import'); + + // Test header errors. + $data[0] = [ + 'Title' => 'Test1', + 'Body' => 'Body1', + 'Redirect' => '', + 'Image' => '', + 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', + 'Created date' => '2015-01-01', + 'Path' => 'news-1', + ]; + $message = $instance->validateHeaders($data); + $this->assertEmpty($message['@Title']); + $this->assertInstanceOf(TranslatableMarkup::class, $message['@Date']); + + // Test No header errors. + $data[0] = [ + 'Title' => 'Test1', + 'Date' => '2015-01-01', + 'Body' => 'Body1', + 'Redirect' => '', + 'Image' => '', + 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', + 'Created date' => '2015-01-01', + 'Path' => 'news-1', + ]; + $message = $instance->validateHeaders($data); + $this->assertEmpty($message); + } + + /** + * Tests CpImport News row validations. + */ + public function testCpImportNewsRowValidation() { + /** @var \Drupal\cp_import\AppImportFactory $appImportFactory */ + $appImportFactory = $this->container->get('app_import_factory'); + $instance = $appImportFactory->create('os_news_import'); + + // Test Title errors. + $data[0] = [ + 'Title' => '', + 'Date' => '2015-01-01', + 'Body' => 'Body1', + 'Redirect' => '', + 'Image' => '', + 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', + 'Created date' => '2015-01-01', + 'Path' => 'news-1', + ]; + $message = $instance->validateRows($data); + $this->assertEmpty($message['@news_date']); + $this->assertInstanceOf(TranslatableMarkup::class, $message['@title']); + + // Test Date field errors. + $data[0] = [ + 'Title' => 'News Title', + 'Date' => '', + 'Body' => 'Body1', + 'Redirect' => '', + 'Image' => '', + 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', + 'Created date' => '2015-01-01', + 'Path' => 'news-1', + ]; + $message = $instance->validateRows($data); + $this->assertEmpty($message['@title']); + $this->assertInstanceOf(TranslatableMarkup::class, $message['@news_date']); + + // Test no errors in row. + $data[0] = [ + 'Title' => 'News Title', + 'Date' => '2015-01-01', + 'Body' => 'Body1', + 'Redirect' => '', + 'Image' => '', + 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', + 'Created date' => '2015-01-01', + 'Path' => 'news-1', + ]; + $message = $instance->validateRows($data); + $this->assertEmpty($message); + } + + /** + * Tests Migration/import for os_news_import. + * + * @throws \Drupal\migrate\MigrateException + * @throws \Drupal\Component\Plugin\Exception\PluginException + */ + public function testCpImportMigrationNews() { + $filename = drupal_get_path('module', 'cp_import_csv_test') . '/artifacts/news.csv'; + $this->cpImportHelper->csvToArray($filename, 'utf-8'); + // Replace existing source file. + $path = 'public://importcsv'; + $this->fileSystem->delete($path . '/os_news.csv'); + $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY); + file_save_data(file_get_contents($filename), $path . '/os_news.csv', FileSystemInterface::EXISTS_REPLACE); + + $storage = $this->entityTypeManager->getStorage('node'); + // Test Negative case. + $node1 = $storage->loadByProperties(['title' => 'Os Title1']); + $this->assertCount(0, $node1); + $node2 = $storage->loadByProperties(['title' => 'Os Title2']); + $this->assertCount(0, $node2); + + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = $this->migrationManager->createInstance('os_news_import'); + $executable = new MigrateExecutable($migration, new MigrateMessage()); + $executable->import(); + + // Test positive case. + $node1 = $storage->loadByProperties(['title' => 'Os Title1']); + $this->assertCount(1, $node1); + $node2 = $storage->loadByProperties(['title' => 'Os Title2']); + $this->assertCount(1, $node2); + + // Import similar content again. + $filename2 = drupal_get_path('module', 'cp_import_csv_test') . '/artifacts/news_small.csv'; + $this->cpImportHelper->csvToArray($filename2, 'utf-8'); + $this->fileSystem->delete($path . '/os_news.csv'); + $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY); + file_save_data(file_get_contents($filename2), $path . '/os_news.csv', FileSystemInterface::EXISTS_REPLACE); + $migration = $this->migrationManager->createInstance('os_news_import'); + $executable = new MigrateExecutable($migration, new MigrateMessage()); + $executable->import(); + // If count is now 2 it means same content is imported again. + $node1 = $storage->loadByProperties(['title' => 'Os Title1']); + $this->assertCount(2, $node1); + + $executable->rollback(); + } + +} From 20998f3456a9622275b0e8342ec7b7dae1384f92 Mon Sep 17 00:00:00 2001 From: Saurabh Pandit <58168562+saurabh-axl@users.noreply.github.com> Date: Fri, 28 Feb 2020 18:26:13 +0530 Subject: [PATCH 16/58] Issue #12845 - Events CSV Import (WIP) (#13084) * Issue #12845 - Events CSV Import * Issue #12845 - Added recurring date support and timezone for import event * Issue #12845 - PR Review Changes --- .../os_events/migrations/os_events_import.yml | 50 +++++ .../os_events/src/Plugin/App/EventsApp.php | 73 +++++- .../cp_import/import_templates/os_event.csv | 5 + .../AppImport/os_events_import/AppImport.php | 209 ++++++++++++++++++ 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 profile/modules/apps/os_events/migrations/os_events_import.yml create mode 100644 profile/modules/cp/modules/cp_import/import_templates/os_event.csv create mode 100644 profile/modules/cp/modules/cp_import/src/AppImport/os_events_import/AppImport.php diff --git a/profile/modules/apps/os_events/migrations/os_events_import.yml b/profile/modules/apps/os_events/migrations/os_events_import.yml new file mode 100644 index 00000000000..37f993c378d --- /dev/null +++ b/profile/modules/apps/os_events/migrations/os_events_import.yml @@ -0,0 +1,50 @@ +id: os_events_import +migration_tags: + - CSV +label: 'Events CSV Import' +source: + plugin: csv + path: public://importcsv/os_event.csv + ids: [Timestamp, Title, Path] + constants: + view: '/calendar/upcoming/' +process: + type: + plugin: default_value + default_value: events + title: Title + body: Body + created: + plugin: format_date + from_format: Y-m-d + to_format: U + source: Created date + field_attached_media/target_id: Files + field_location: Location + field_signup: Registration + field_recurring_date/value: + plugin: format_date + from_format: 'Y-m-d h:i A' + to_format: 'Y-m-d\TH:i:s' + source: Start date + field_recurring_date/end_value: + plugin: format_date + from_format: 'Y-m-d h:i A' + to_format: 'Y-m-d\TH:i:s' + source: End date + field_recurring_date/timezone: + plugin: default_value + default_value: 'America/New_York' + path/pathauto: + plugin: default_value + default_value: 0 # Disable pathauto + path/alias: + plugin: concat + source: + - constants/view + - Path +destination: + plugin: 'entity:node' +migration_dependencies: + required: { } + optional: { } diff --git a/profile/modules/apps/os_events/src/Plugin/App/EventsApp.php b/profile/modules/apps/os_events/src/Plugin/App/EventsApp.php index 36603202865..b0f7d4bd112 100644 --- a/profile/modules/apps/os_events/src/Plugin/App/EventsApp.php +++ b/profile/modules/apps/os_events/src/Plugin/App/EventsApp.php @@ -2,7 +2,14 @@ namespace Drupal\os_events\Plugin\App; +use Drupal\Core\Entity\EntityTypeManager; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Drupal\cp_import\AppImportFactory; +use Drupal\cp_import\Helper\CpImportHelper; +use Drupal\migrate\Plugin\MigrationPluginManager; use Drupal\vsite\Plugin\AppPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Events app. @@ -29,9 +36,73 @@ * }, * }, * id = "event", - * contextualRoute = "view.upcoming_calendar.page" + * contextualRoute = "view.upcoming_calendar.page", + * cpImportId = "os_events_import", + * cpImportFilePath = "public://importcsv/os_event.csv" * ) */ class EventsApp extends AppPluginBase { + /** + * App Import factory service. + * + * @var \Drupal\cp_import\AppImportFactory + */ + protected $appImportFactory; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationPluginManager $migrationPluginManager, CpImportHelper $cpImportHelper, Messenger $messenger, EntityTypeManager $entityTypeManager, AppImportFactory $appImportFactory) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migrationPluginManager, $cpImportHelper, $messenger, $entityTypeManager); + $this->appImportFactory = $appImportFactory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.migration'), + $container->get('cp_import.helper'), + $container->get('messenger'), + $container->get('entity_type.manager'), + $container->get('app_import_factory') + ); + } + + /** + * Validates import file and shows errors row wise. + * + * @param array $form + * The form. + * @param \Drupal\Core\Form\FormStateInterface $formState + * The Form State. + */ + public function validateImportSource(array $form, FormStateInterface $formState) { + $data = parent::validateImportSource($form, $formState); + if (!$data) { + return; + } + + $definition = $this->getPluginDefinition(); + $eventImport = $this->appImportFactory->create($definition['cpImportId']); + + // Validate Headers. + if ($missing = $eventImport->validateHeaders($data)) { + $headerMessage = $this->t('The following Header/columns are missing:
      @Title @Body @Start date @End date @Location @Registration @Files @Created date @Path

    The structure of your CSV file probably needs to be updated. Please download the template again.', $missing); + $this->messenger->addError($headerMessage); + $formState->setError($form['import_file']); + return; + } + + // Validate rows. + if ($message = $eventImport->validateRows($data)) { + $formState->setError($form['import_file']); + $this->messenger->addError($this->t('@title @file @date', $message)); + } + } } diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_event.csv b/profile/modules/cp/modules/cp_import/import_templates/os_event.csv new file mode 100644 index 00000000000..00e8507d861 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/import_templates/os_event.csv @@ -0,0 +1,5 @@ +Title,Body,Start date,End date,Location,Registration,Files,Created date,Path +Event with registration (including hour),This is event with registration,2020-11-30 3:20 PM,2020-11-30 3:50 PM,Boston,On,http://college.harvard.edu/sites/default/files/harvard-fy.pdf,2020-12-31, +Event without registration (including hour),This is event without registration,2020-9-20 3:20 PM,2020-9-20 3:50 PM,Toronto,,http://college.harvard.edu/sites/default/files/harvard-fy.pdf,2020-12-31, +Event with registration,This is event with registration,2020-5-15,2020-5-15,Boston,On,http://college.harvard.edu/sites/default/files/harvard-fy.pdf,2020-12-31, +Event without registration,This is event without registration,2020-6-20,2020-6-20,Toronto,,http://college.harvard.edu/sites/default/files/harvard-fy.pdf,2020-12-31, diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_events_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_events_import/AppImport.php new file mode 100644 index 00000000000..327da7916b9 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_events_import/AppImport.php @@ -0,0 +1,209 @@ +getRow(); + $dest_val = $row->getDestination(); + $media_val = $dest_val['field_attached_media']['target_id']; + // If not a valid url return and don't do anything , this reduces the risk + // of malicious scripts as we do not want to support HTML media from here. + if (!UrlHelper::isValid($media_val)) { + return; + } + // Get the media. + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type); + if ($media_entity) { + $row->setDestinationProperty('field_attached_media/target_id', $media_entity->id()); + } + $row->setDestinationProperty('field_recurring_date/timezone', drupal_get_user_timezone()); + } + + /** + * {@inheritdoc} + */ + public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { + $ids = $event->getDestinationIdValues(); + foreach ($ids as $id) { + $this->cpImportHelper->addContentToVsite($id, $this->groupPluginId, 'node'); + } + parent::migratePostRowSaveActions($event); + } + + /** + * {@inheritdoc} + */ + public function prepareRowActions(MigratePrepareRowEvent $event) { + $source = $event->getRow()->getSource(); + $createdDate = $source['Created date']; + if ($createdDate) { + $date = DateTime::createFromFormat('Y-m-d', $createdDate); + if ($date->format('Y-n-j') == $createdDate) { + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } + } + else { + $date = new DateTime(); + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } + + $start_date = strtoupper($source['Start date']); + $date = DateTime::createFromFormat('Y-m-d', $start_date); + if ($date && $date->format('Y-m-d') == $start_date) { + $start_date = $date->format('Y-m-d H:i A'); + } + $event->getRow()->setSourceProperty('Start date', $start_date); + + $end_date = strtoupper($source['End date']); + $date = DateTime::createFromFormat('Y-m-d', $end_date); + if ($date && $date->format('Y-m-d') == $end_date) { + $end_date = $date->format('Y-m-d H:i A'); + } + $event->getRow()->setSourceProperty('End date', $end_date); + + $signup_status = $source['Registration']; + $signup_flag = FALSE; + if (strtolower($signup_status) == 'on') { + $signup_flag = TRUE; + } + $event->getRow()->setSourceProperty('Registration', $signup_flag); + parent::prepareRowActions($event); + } + + /** + * Validates headers from csv file array. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateHeaders(array $data): array { + $headerMissing = FALSE; + $eventsHeaders = [ + 'Title', + 'Body', + 'Start date', + 'End date', + 'Location', + 'Registration', + 'Files', + 'Created date', + 'Path', + ]; + $missing = [ + '@Title' => '', + '@Body' => '', + '@Start date' => '', + '@End date' => '', + '@Location' => '', + '@Registration' => '', + '@Files' => '', + '@Created date' => '', + '@Path' => '', + ]; + + foreach ($data as $row) { + $columnHeaders = array_keys($row); + foreach ($eventsHeaders as $eventsHeader) { + if (!in_array($eventsHeader, $columnHeaders)) { + $missing['@' . $eventsHeader] = $this->t('
  • @column
  • ', ['@column' => $eventsHeader]); + $headerMissing = TRUE; + } + } + } + return $headerMissing ? $missing : []; + } + + /** + * Validates Rows for csv import. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateRows(array $data) : array { + $hasError = FALSE; + $titleRows = ''; + $fileRows = ''; + $dateRows = ''; + $message = [ + '@title' => '', + '@file' => '', + '@date' => '', + ]; + + foreach ($data as $delta => $row) { + $row_number = ++$delta; + // Validate Title. + if (!$row['Title']) { + $titleRows .= $row_number . ','; + } + // Validate File url. + if ($url = $row['Files']) { + $headers = get_headers($url, 1); + if (strpos($headers[0], '200') === FALSE) { + $fileRows .= $row_number . ','; + } + } + // Validate Date. + if ($createdDate = $row['Created date']) { + $date = DateTime::createFromFormat('Y-m-d', $createdDate); + if (!$date || !($date->format('Y-m-d') == $createdDate || $date->format('Y-n-j') == $createdDate)) { + $dateRows .= $row_number . ','; + } + } + } + $titleRows = rtrim($titleRows, ','); + if ($titleRows) { + $message['@title'] = $this->t('Title is required for row/rows @titleRows
    ', ['@titleRows' => $titleRows]); + $hasError = TRUE; + } + $fileRows = rtrim($fileRows, ','); + if ($fileRows) { + $message['@file'] = $this->t('File url is invalid for row/rows @fileRows
    ', ['@fileRows' => $fileRows]); + $hasError = TRUE; + } + $dateRows = rtrim($dateRows, ','); + if ($dateRows) { + $message['@date'] = $this->t('Date/Date Format is invalid for row/rows @dateRows
    ', ['@dateRows' => $dateRows]); + $hasError = TRUE; + } + return $hasError ? $message : []; + } + +} From 59df6d29055168110bc520833f07a2284fb11a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Mon, 2 Mar 2020 05:53:29 +0100 Subject: [PATCH 17/58] Issue #12947 - CI refactorings (#13109) * Issue #12947 - Remove listing commands * Issue #12947 - Add extra comments * Issue #12947 - Move unit test into test stage --- .travis.yml | 4 ++-- .travis/RoboFile.php | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7992c508d67..4f4a1d26503 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,10 +36,10 @@ jobs: include: - stage: prepare for tests script: robo job:check-coding-standards - - stage: prepare for tests - script: robo job:run-unit-tests - stage: prepare for tests script: robo job:check-module-circular-dependency + - stage: test + script: robo job:run-unit-tests - stage: test script: robo job:run-kernel-tests "widgets-1,widgets-2,widgets-3,widgets-4,widgets-5" - stage: test diff --git a/.travis/RoboFile.php b/.travis/RoboFile.php index e4fe69c23a2..ccf0458ecf3 100644 --- a/.travis/RoboFile.php +++ b/.travis/RoboFile.php @@ -252,7 +252,6 @@ protected function buildEnvironment() $tasks[] = $this->taskExec('aws s3 sync s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER .'); $tasks[] = $this->taskExec('tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz'); $tasks[] = $this->taskExec('sudo chown -R 1000:1000 custom_themes'); - $tasks[] = $this->taskExec('ls -la'); return $tasks; } @@ -271,7 +270,6 @@ protected function importDatabase() $tasks[] = $this->taskExec('sudo tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-settings.tar.xz web/sites/default'); $tasks[] = $this->taskExec('sudo tar -Jxf os-build-${TRAVIS_BUILD_NUMBER}-files.tar.xz web/sites/default'); $tasks[] = $this->taskExec('sudo chown -R 1000:1000 web/sites/default'); - $tasks[] = $this->taskExec('ls -la'); // Import sql. $tasks[] = $this->taskExec('docker-compose exec -T php drush sqlq --file=./travis-backup.sql'); @@ -287,11 +285,12 @@ protected function importDatabase() protected function uploadToAws() { $tasks[] = $this->taskExec('docker-compose exec -T php drush sql-dump --result-file=./travis-backup.sql'); - $tasks[] = $this->taskExec('ls -la'); + // Build the artifacts. $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-db.tar.xz web/travis-backup.sql'); $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-settings.tar.xz web/sites/default/settings.php'); $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz custom_themes'); $tasks[] = $this->taskExec('tar -Jcf ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-files.tar.xz web/sites/default/files'); + // Upload the artifacts. $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-db.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-db.tar.xz'); $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-settings.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-settings.tar.xz'); $tasks[] = $this->taskExec('aws s3 cp ${TRAVIS_BUILD_DIR}-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz s3://$ARTIFACTS_BUCKET/build_files/$TRAVIS_BUILD_NUMBER/os-build-${TRAVIS_BUILD_NUMBER}-custom_themes.tar.xz'); From 9a193e0a94dbd6b32e70489b9ffc2f54ff781d2f Mon Sep 17 00:00:00 2001 From: mukeyshkumar <47223502+mukeyshkumar@users.noreply.github.com> Date: Mon, 2 Mar 2020 11:10:38 +0530 Subject: [PATCH 18/58] Issue #13115 - theme name changes (#13116) --- profile/themes/branded_theme/branded_theme.info.yml | 4 ++-- profile/themes/themeone/themeone.info.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/profile/themes/branded_theme/branded_theme.info.yml b/profile/themes/branded_theme/branded_theme.info.yml index 2317ca5e0ba..ab9e20dce05 100644 --- a/profile/themes/branded_theme/branded_theme.info.yml +++ b/profile/themes/branded_theme/branded_theme.info.yml @@ -1,5 +1,5 @@ -name: 'Branded theme' -description: 'A modern looking theme for use by departments at Harvard.' +name: 'Branded' +description: 'A branded looking theme for use by departments at Harvard.' base theme: os_base core: 8.x diff --git a/profile/themes/themeone/themeone.info.yml b/profile/themes/themeone/themeone.info.yml index 462df9ecc1a..69879a6cbea 100644 --- a/profile/themes/themeone/themeone.info.yml +++ b/profile/themes/themeone/themeone.info.yml @@ -1,5 +1,5 @@ -name: 'Themeone' -description: 'Themeone theme.' +name: 'Clementine' +description: 'Clementine theme.' base theme: os_base core: 8.x From 23173162d59fbb41afbf2fdca3b65e03cc69f3e6 Mon Sep 17 00:00:00 2001 From: Lomas Rishi Gupta Date: Mon, 2 Mar 2020 13:26:48 +0530 Subject: [PATCH 19/58] Issue #13108 - Support MM/DD/YYYY format during import (#13111) * Issue #12843 - 12843-import-person-content-development * Issue #12843 - 12843 includes change in cp helper function and tests * Issue #12843 - adds 3rd argument in getMedia function * Issue #12843 - fixing testCpImportHelperMediaCreation test * Issue #13108 - 13108-support-new-date-format * Issue #13108 - Support MM/DD/YYYY format during import * Issue #13108 - 13108-support-new-date-format-profiles * Issue #13108 - job 6 test fix * Issue #13108 - import-person-content adds date mm-dd-YYYY * Issue #13108 - 13108-fix for testCpImportMigrationFaq * Issue #13108 - 13108-fix for testCpImportMigrationFaq * Issue #13108 - New date format with changes in all migrations scripts * Issue #13108 - adds constant CUSTOM_DATE_FORMAT --- .../migrations/os_profiles_import.yml | 50 ++++ .../src/Plugin/App/ProfilesApp.php | 74 +++++- .../cp_import/import_templates/os_blog.csv | 2 +- .../cp_import/import_templates/os_faq.csv | 2 +- .../import_templates/os_profiles.csv | 2 + .../import_templates/os_software.csv | 2 +- .../modules/cp_import/src/AppImport/Base.php | 15 ++ .../AppImport/os_blog_import/AppImport.php | 26 +-- .../src/AppImport/os_faq_import/AppImport.php | 26 +-- .../os_profiles_import/AppImport.php | 220 ++++++++++++++++++ .../os_software_import/AppImport.php | 26 +-- .../cp_import/src/Helper/CpImportHelper.php | 16 +- .../cp_import_csv_test/artifacts/blog.csv | 12 +- .../artifacts/blog_small.csv | 8 +- .../cp_import_csv_test/artifacts/faq.csv | 16 +- .../artifacts/faq_small.csv | 8 +- .../cp_import_csv_test/artifacts/profiles.csv | 7 + .../artifacts/profiles_small.csv | 7 + .../cp_import_csv_test/artifacts/software.csv | 14 +- .../artifacts/software_small.csv | 8 +- .../ExistingSite/CpImportFunctionalTest.php | 21 +- .../tests/src/ExistingSite/CpImportTest.php | 154 ++++++++++-- 22 files changed, 589 insertions(+), 127 deletions(-) create mode 100644 profile/modules/apps/os_profiles/migrations/os_profiles_import.yml create mode 100644 profile/modules/cp/modules/cp_import/import_templates/os_profiles.csv create mode 100644 profile/modules/cp/modules/cp_import/src/AppImport/os_profiles_import/AppImport.php create mode 100644 profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles.csv create mode 100644 profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles_small.csv diff --git a/profile/modules/apps/os_profiles/migrations/os_profiles_import.yml b/profile/modules/apps/os_profiles/migrations/os_profiles_import.yml new file mode 100644 index 00000000000..ae0eb581b3d --- /dev/null +++ b/profile/modules/apps/os_profiles/migrations/os_profiles_import.yml @@ -0,0 +1,50 @@ +id: os_profiles_import +migration_tags: + - CSV +label: 'CSV file migration' +source: + plugin: csv + path: public://importcsv/os_profiles.csv + ids: [Timestamp, Email, Path] + constants: + view: '/profiles/' +process: + type: + plugin: default_value + default_value: person + body: Short bio + field_honorific: Prefix + field_first_name: First name + field_middle_name: Middle name + field_last_name: Last name + field_email: Email + field_address: Address + field_phone: Phone + field_professional_titles/0: Title 1 + field_professional_titles/1: Title 2 + field_professional_titles/2: Title 3 + field_website: + plugin: iterator + source: links + process: + title: title + uri: uri + created: + plugin: format_date + from_format: Y-m-d + to_format: U + source: Created date + field_photo_person/target_id: Photo + path/pathauto: + plugin: default_value + default_value: 0 # Disable pathauto + path/alias: + plugin: concat + source: + - constants/view + - Path +destination: + plugin: 'entity:node' +migration_dependencies: + required: { } + optional: { } diff --git a/profile/modules/apps/os_profiles/src/Plugin/App/ProfilesApp.php b/profile/modules/apps/os_profiles/src/Plugin/App/ProfilesApp.php index 01101ebdf77..373e7530cb0 100644 --- a/profile/modules/apps/os_profiles/src/Plugin/App/ProfilesApp.php +++ b/profile/modules/apps/os_profiles/src/Plugin/App/ProfilesApp.php @@ -2,7 +2,14 @@ namespace Drupal\os_profiles\Plugin\App; +use Drupal\Core\Entity\EntityTypeManager; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Drupal\cp_import\AppImportFactory; +use Drupal\cp_import\Helper\CpImportHelper; +use Drupal\migrate\Plugin\MigrationPluginManager; use Drupal\vsite\Plugin\AppPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Profiles app. @@ -12,7 +19,7 @@ * canDisable = true, * entityType = "node", * bundle = { - * "person" + * "person" * }, * viewsTabs = { * "people" = { @@ -21,8 +28,73 @@ * }, * id = "profiles", * contextualRoute = "view.people.page_1", + * cpImportId = "os_profiles_import", + * cpImportFilePath = "public://importcsv/os_profiles.csv" * ) */ class ProfilesApp extends AppPluginBase { + /** + * App Import factory service. + * + * @var \Drupal\cp_import\AppImportFactory + */ + protected $appImportFactory; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationPluginManager $migrationPluginManager, CpImportHelper $cpImportHelper, Messenger $messenger, EntityTypeManager $entityTypeManager, AppImportFactory $appImportFactory) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migrationPluginManager, $cpImportHelper, $messenger, $entityTypeManager); + $this->appImportFactory = $appImportFactory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.migration'), + $container->get('cp_import.helper'), + $container->get('messenger'), + $container->get('entity_type.manager'), + $container->get('app_import_factory') + ); + } + + /** + * Validates import file and shows errors row wise. + * + * @param array $form + * The form. + * @param \Drupal\Core\Form\FormStateInterface $formState + * The Form State. + */ + public function validateImportSource(array $form, FormStateInterface $formState) { + $data = parent::validateImportSource($form, $formState); + if (!$data) { + return; + } + + $definition = $this->getPluginDefinition(); + $faqImport = $this->appImportFactory->create($definition['cpImportId']); + + // Validate Headers. + if ($missing = $faqImport->validateHeaders($data)) { + $headerMessage = $this->t('The following Header/columns are missing:
      @First name @Last name @Photo @Created date @Path

    The structure of your CSV file probably needs to be updated. Please download the template again.', $missing); + $this->messenger->addError($headerMessage); + $formState->setError($form['import_file']); + return; + } + + // Validate rows. + if ($message = $faqImport->validateRows($data)) { + $formState->setError($form['import_file']); + $this->messenger->addError($this->t('@firstNameRows @lastNameRows @photo @email @date', $message)); + } + } + } diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv b/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv index 0fec7f9e24d..05100efe180 100644 --- a/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv +++ b/profile/modules/cp/modules/cp_import/import_templates/os_blog.csv @@ -1,2 +1,2 @@ Title,Body,Files,Created date,Path -Blog title,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,my-blog +Blog title,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/24/2014,my-blog diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_faq.csv b/profile/modules/cp/modules/cp_import/import_templates/os_faq.csv index 61ba5e14201..7436a3793cf 100755 --- a/profile/modules/cp/modules/cp_import/import_templates/os_faq.csv +++ b/profile/modules/cp/modules/cp_import/import_templates/os_faq.csv @@ -1,2 +1,2 @@ Title,Body,Files,Created date,Path -Some Question,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-11-30,some-question +Some Question,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,11/30/2020,some-question diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_profiles.csv b/profile/modules/cp/modules/cp_import/import_templates/os_profiles.csv new file mode 100644 index 00000000000..d84e7ac3801 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/import_templates/os_profiles.csv @@ -0,0 +1,2 @@ +Prefix,First name,Middle name,Last name,Photo,Title 1,Title 2,Title 3,Address,Phone,Email,Websites title 1,Websites url 1,Websites title 2,Websites url 2,Websites title 3,Websites url 3,Short bio,Created date,Path +Mr.,Homer,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,11/12/2015,homer-simpson diff --git a/profile/modules/cp/modules/cp_import/import_templates/os_software.csv b/profile/modules/cp/modules/cp_import/import_templates/os_software.csv index d925f418299..7c63b678d3b 100755 --- a/profile/modules/cp/modules/cp_import/import_templates/os_software.csv +++ b/profile/modules/cp/modules/cp_import/import_templates/os_software.csv @@ -1,2 +1,2 @@ Title,Body,Files,Created date,Path -Some Software,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,2020-11-30,some-software +Some Software,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,11/11/2014,some-software diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/Base.php b/profile/modules/cp/modules/cp_import/src/AppImport/Base.php index f012146d09e..d11ee4b74a6 100644 --- a/profile/modules/cp/modules/cp_import/src/AppImport/Base.php +++ b/profile/modules/cp/modules/cp_import/src/AppImport/Base.php @@ -2,6 +2,7 @@ namespace Drupal\cp_import\AppImport; +use DateTime; use Drupal\Core\Language\LanguageManager; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\cp_import\Helper\CpImportHelper; @@ -17,6 +18,11 @@ abstract class Base implements BaseInterface { use StringTranslationTrait; + /** + * Custom date format. + */ + public const CUSTOM_DATE_FORMAT = "m/d/Y"; + /** * Cp Import helper service. * @@ -60,6 +66,7 @@ public function __construct(CpImportHelper $cpImportHelper, VsiteAliasStorage $v public function prepareRowActions(MigratePrepareRowEvent $event) { $source = $event->getRow()->getSource(); $type = $event->getMigration()->getProcess()['type'][0]['default_value']; + $createdDate = $source['Created date']; if ($alias = $source['Path']) { if ($this->vsiteAliasStorage->aliasExists("/$type/$alias", $this->languageManager->getDefaultLanguage()->getId())) { $event->getRow()->setSourceProperty('NeedsAliasUpdate', TRUE); @@ -68,6 +75,14 @@ public function prepareRowActions(MigratePrepareRowEvent $event) { else { $event->getRow()->setSourceProperty('NeedsAliasUpdate', TRUE); } + if ($createdDate) { + $date = DateTime::createFromFormat(Base::CUSTOM_DATE_FORMAT, $createdDate); + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } + else { + $date = new DateTime(); + $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); + } } /** diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_blog_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_blog_import/AppImport.php index 746ede56446..f49753d5363 100644 --- a/profile/modules/cp/modules/cp_import/src/AppImport/os_blog_import/AppImport.php +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_blog_import/AppImport.php @@ -7,7 +7,6 @@ use Drupal\cp_import\AppImport\Base; use Drupal\migrate\Event\MigratePostRowSaveEvent; use Drupal\migrate\Event\MigratePreRowSaveEvent; -use Drupal\migrate_plus\Event\MigratePrepareRowEvent; /** * Class AppImport. @@ -43,7 +42,7 @@ public function preRowSaveActions(MigratePreRowSaveEvent $event) { return; } // Get the media. - $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type); + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type, 'field_attached_media'); if ($media_entity) { $row->setDestinationProperty('field_attached_media/target_id', $media_entity->id()); } @@ -60,25 +59,6 @@ public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { parent::migratePostRowSaveActions($event); } - /** - * {@inheritdoc} - */ - public function prepareRowActions(MigratePrepareRowEvent $event) { - $source = $event->getRow()->getSource(); - $createdDate = $source['Created date']; - if ($createdDate) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if ($date->format('Y-n-j') == $createdDate) { - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - } - else { - $date = new DateTime(); - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - parent::prepareRowActions($event); - } - /** * Validates headers from csv file array. * @@ -146,8 +126,8 @@ public function validateRows(array $data) : array { } // Validate Date. if ($createdDate = $row['Created date']) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if (!$date || !($date->format('Y-m-d') == $createdDate || $date->format('Y-n-j') == $createdDate)) { + $date = DateTime::createFromFormat(Base::CUSTOM_DATE_FORMAT, $createdDate); + if (!$date || !($date->format(Base::CUSTOM_DATE_FORMAT) == $createdDate || $date->format('n-j-Y') == $createdDate)) { $dateRows .= $row_number . ','; } } diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_faq_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_faq_import/AppImport.php index 151bee84141..5c2dbc65ed7 100644 --- a/profile/modules/cp/modules/cp_import/src/AppImport/os_faq_import/AppImport.php +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_faq_import/AppImport.php @@ -7,7 +7,6 @@ use Drupal\cp_import\AppImport\Base; use Drupal\migrate\Event\MigratePostRowSaveEvent; use Drupal\migrate\Event\MigratePreRowSaveEvent; -use Drupal\migrate_plus\Event\MigratePrepareRowEvent; /** * Class AppImport. @@ -43,7 +42,7 @@ public function preRowSaveActions(MigratePreRowSaveEvent $event) { return; } // Get the media. - $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type); + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type, 'field_attached_media'); if ($media_entity) { $row->setDestinationProperty('field_attached_media/target_id', $media_entity->id()); } @@ -60,25 +59,6 @@ public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { parent::migratePostRowSaveActions($event); } - /** - * {@inheritdoc} - */ - public function prepareRowActions(MigratePrepareRowEvent $event) { - $source = $event->getRow()->getSource(); - $createdDate = $source['Created date']; - if ($createdDate) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if ($date->format('Y-n-j') == $createdDate) { - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - } - else { - $date = new DateTime(); - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - parent::prepareRowActions($event); - } - /** * Validates headers from csv file array. * @@ -151,8 +131,8 @@ public function validateRows(array $data) : array { } // Validate Date. if ($createdDate = $row['Created date']) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if (!$date || !($date->format('Y-m-d') == $createdDate || $date->format('Y-n-j') == $createdDate)) { + $date = DateTime::createFromFormat(Base::CUSTOM_DATE_FORMAT, $createdDate); + if (!$date || !($date->format(Base::CUSTOM_DATE_FORMAT) == $createdDate || $date->format('n/j/Y') == $createdDate)) { $dateRows .= $row_number . ','; } } diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_profiles_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_profiles_import/AppImport.php new file mode 100644 index 00000000000..eb6a9dea334 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_profiles_import/AppImport.php @@ -0,0 +1,220 @@ +getRow(); + $dest_val = $row->getDestination(); + $media_val = $dest_val['field_photo_person']['target_id']; + $media_alt = $dest_val['field_first_name'] . '_' . $dest_val['field_last_name']; + // If not a valid url return and don't do anything , this reduces the risk + // of malicious scripts as we do not want to support HTML media from here. + if (!UrlHelper::isValid($media_val)) { + return; + } + // Get the media. + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type, 'field_photo_person'); + if ($media_entity) { + $file = Media::load($media_entity->id()); + $image = [ + [ + 'target_id' => $file->get('field_media_image')->getValue()[0]['target_id'], + 'alt' => $media_alt, + ], + ]; + $row->setDestinationProperty('field_photo_person', $image); + } + } + + /** + * {@inheritdoc} + */ + public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { + $ids = $event->getDestinationIdValues(); + foreach ($ids as $id) { + $this->cpImportHelper->addContentToVsite($id, $this->groupPluginId, 'node'); + } + parent::migratePostRowSaveActions($event); + } + + /** + * {@inheritdoc} + */ + public function prepareRowActions(MigratePrepareRowEvent $event) { + $source = $event->getRow()->getSource(); + $links = [ + [ + 'title' => $source['Websites title 1'], + 'uri' => $source['Websites url 1'], + ], + [ + 'title' => $source['Websites title 2'], + 'uri' => $source['Websites url 2'], + ], + [ + 'title' => $source['Websites title 3'], + 'uri' => $source['Websites url 3'], + ], + ]; + $event->getRow()->setSourceProperty('links', $links); + parent::prepareRowActions($event); + } + + /** + * Validates headers from csv file array. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateHeaders(array $data): array { + $headerMissing = FALSE; + $faqHeaders = [ + 'First name', + 'Last name', + 'Photo', + 'Created date', + 'Email', + 'Path', + ]; + $missing = [ + '@First name' => '', + '@Last name' => '', + '@Photo' => '', + '@Created date' => '', + '@Email' => '', + '@Path' => '', + ]; + + foreach ($data as $row) { + $columnHeaders = array_keys($row); + foreach ($faqHeaders as $faqHeader) { + if (!in_array($faqHeader, $columnHeaders)) { + $missing['@' . $faqHeader] = $this->t('
  • @column
  • ', ['@column' => $faqHeader]); + $headerMissing = TRUE; + } + } + } + return $headerMissing ? $missing : []; + } + + /** + * Validates Rows for csv import. + * + * @param array $data + * Array derived from csv file. + * + * @return array + * Missing errors or empty if no errors. + */ + public function validateRows(array $data) : array { + $hasError = FALSE; + $firstNameRows = ''; + $lastNameRows = ''; + $photoRows = ''; + $dateRows = ''; + $emailRows = ''; + $message = [ + '@firstNameRows' => '', + '@lastNameRows' => '', + '@photo' => '', + '@date' => '', + '@email' => '', + ]; + + foreach ($data as $delta => $row) { + $row_number = ++$delta; + // Validate First Name. + if (!$row['First name']) { + $firstNameRows .= $row_number . ','; + } + // Validate Last Name. + if (!$row['Last name']) { + $lastNameRows .= $row_number . ','; + } + // Validate Photo url. + if ($url = $row['Photo']) { + $headers = get_headers($url, 1); + if (strpos($headers[0], '200') === FALSE) { + $photoRows .= $row_number . ','; + } + } + // Validate Date. + if ($createdDate = $row['Created date']) { + $date = DateTime::createFromFormat(Base::CUSTOM_DATE_FORMAT, $createdDate); + if (!$date || !($date->format(Base::CUSTOM_DATE_FORMAT) == $createdDate || $date->format('n-j-Y') == $createdDate)) { + $dateRows .= $row_number . ','; + } + } + // Validate Email. + if ($email = $row['Email']) { + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $emailRows .= $row_number . ','; + + } + } + } + $firstNameRows = rtrim($firstNameRows, ','); + if ($firstNameRows) { + $message['@firstNameRows'] = $this->t('First name is required for row/rows @firstNameRows
    ', ['@firstNameRows' => $firstNameRows]); + $hasError = TRUE; + } + $lastNameRows = rtrim($lastNameRows, ','); + if ($lastNameRows) { + $message['@lastNameRows'] = $this->t('Last name is required for row/rows @lastNameRows
    ', ['@lastNameRows' => $lastNameRows]); + $hasError = TRUE; + } + $photoRows = rtrim($photoRows, ','); + if ($photoRows) { + + $message['@photo'] = $this->t('Photo url is invalid for row/rows @photo
    ', ['@photo' => $photoRows]); + $hasError = TRUE; + } + $dateRows = rtrim($dateRows, ','); + if ($dateRows) { + $message['@date'] = $this->t('Date/Date Format is invalid for row/rows @dateRows
    ', ['@dateRows' => $dateRows]); + $hasError = TRUE; + } + $emailRows = rtrim($emailRows, ','); + if ($emailRows) { + $message['@email'] = $this->t('Email/Email Format is invalid for row/rows @emailRows
    ', ['@emailRows' => $emailRows]); + $hasError = TRUE; + } + return $hasError ? $message : []; + } + +} diff --git a/profile/modules/cp/modules/cp_import/src/AppImport/os_software_import/AppImport.php b/profile/modules/cp/modules/cp_import/src/AppImport/os_software_import/AppImport.php index e8fd4729608..6bcc25b98f4 100644 --- a/profile/modules/cp/modules/cp_import/src/AppImport/os_software_import/AppImport.php +++ b/profile/modules/cp/modules/cp_import/src/AppImport/os_software_import/AppImport.php @@ -7,7 +7,6 @@ use Drupal\cp_import\AppImport\Base; use Drupal\migrate\Event\MigratePostRowSaveEvent; use Drupal\migrate\Event\MigratePreRowSaveEvent; -use Drupal\migrate_plus\Event\MigratePrepareRowEvent; /** * Handles Software Import. @@ -43,7 +42,7 @@ public function preRowSaveActions(MigratePreRowSaveEvent $event) { return; } // Get the media. - $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type); + $media_entity = $this->cpImportHelper->getMedia($media_val, $this->type, 'field_attached_media'); if ($media_entity) { $row->setDestinationProperty('field_attached_media/target_id', $media_entity->id()); } @@ -60,25 +59,6 @@ public function migratePostRowSaveActions(MigratePostRowSaveEvent $event) { parent::migratePostRowSaveActions($event); } - /** - * {@inheritdoc} - */ - public function prepareRowActions(MigratePrepareRowEvent $event) { - $source = $event->getRow()->getSource(); - $createdDate = $source['Created date']; - if ($createdDate) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if ($date->format('Y-n-j') == $createdDate) { - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - } - else { - $date = new DateTime(); - $event->getRow()->setSourceProperty('Created date', $date->format('Y-m-d')); - } - parent::prepareRowActions($event); - } - /** * Validates headers from csv file array. * @@ -144,8 +124,8 @@ public function validateRows(array $data) : array { } // Validate Date. if ($createdDate = $row['Created date']) { - $date = DateTime::createFromFormat('Y-m-d', $createdDate); - if (!$date || !($date->format('Y-m-d') == $createdDate || $date->format('Y-n-j') == $createdDate)) { + $date = DateTime::createFromFormat(Base::CUSTOM_DATE_FORMAT, $createdDate); + if (!$date || !($date->format(Base::CUSTOM_DATE_FORMAT) == $createdDate || $date->format('n-j-Y') == $createdDate)) { $dateRows .= $row_number . ','; } } diff --git a/profile/modules/cp/modules/cp_import/src/Helper/CpImportHelper.php b/profile/modules/cp/modules/cp_import/src/Helper/CpImportHelper.php index 7d17b69b05a..88f6a6e6002 100644 --- a/profile/modules/cp/modules/cp_import/src/Helper/CpImportHelper.php +++ b/profile/modules/cp/modules/cp_import/src/Helper/CpImportHelper.php @@ -135,6 +135,8 @@ public function __construct(VsiteContextManager $vsiteContextManager, EntityType * The media value entered in the csv. * @param string $contentType * Content type. + * @param string $field_name + * Media field name. * * @return \Drupal\media\Entity\Media|null * Media entity/Null when not able to fetch/download media. @@ -143,16 +145,22 @@ public function __construct(VsiteContextManager $vsiteContextManager, EntityType * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Core\Entity\EntityStorageException */ - public function getMedia($media_val, $contentType) : ?Media { + public function getMedia($media_val, $contentType, $field_name) : ?Media { $media = NULL; // Only load the bundles which are enabled for the content type's field. $bundle_fields = $this->fieldManager->getFieldDefinitions('node', $contentType); - $field_definition = $bundle_fields['field_attached_media']; + $field_definition = $bundle_fields[$field_name]; $settings = $field_definition->getSettings(); - $bundles = $settings['handler_settings']['target_bundles']; + if (!empty($settings['handler_settings'])) { + $bundles = $settings['handler_settings']['target_bundles']; + } + elseif ($settings['target_type'] === 'file') { + $bundles = [ + 'image' => 'image', + ]; + } /** @var \Drupal\media\Entity\MediaType[] $mediaTypes */ $mediaTypes = $this->entityTypeManager->getStorage('media_type')->loadMultiple($bundles); - $item = get_headers($media_val, 1); $type = $item['Content-Type']; // If there is a redirection then only get the value of the last page. diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog.csv index a0248c9a30a..ee9f1cf7ecf 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog.csv @@ -1,7 +1,7 @@ Title,Body,Files,Created date,Path -Test Blog 1,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-1 -Test Blog 2,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-2 -Test Blog 3,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-3 -Test Blog 4,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-4 -Test Blog 5,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-5 -Test Blog 6,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-6 +Test Blog 1,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-1 +Test Blog 2,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-2 +Test Blog 3,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-3 +Test Blog 4,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-4 +Test Blog 5,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-5 +Test Blog 6,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-6 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog_small.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog_small.csv index bf6bf7d7f46..2e8f736ebb2 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog_small.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/blog_small.csv @@ -1,5 +1,5 @@ Title,Body,Files,Created date,Path -Test Blog 1,Text,,2020-12-31,test-blog-small-1 -Test Blog 2,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-small-2 -Test Blog 3,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-small-3 -Test Blog 4,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,2020-12-31,test-blog-small-4 +Test Blog 1,Text,,12/31/2020,test-blog-small-1 +Test Blog 2,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-small-2 +Test Blog 3,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-small-3 +Test Blog 4,Text,https://hwpi.harvard.edu/files/torman_fileserver/files/lady6.png,12/31/2020,test-blog-small-4 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq.csv index dcc9f2f5ac6..78bb96042ae 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq.csv @@ -1,11 +1,11 @@ Title,Body,Files,Created date,Path -Some Question 1,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,2014-1-1,some-question1 -Some Question 2,Text,,2014-1-1,some-question2 +Some Question 1,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,01/01/2014,some-question1 +Some Question 2,Text,,01/01/2014,some-question2 Some Question 3,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,some-question3 -Some Question 4,Text,,2014-01-01,some-question4 -Some Question 5,Text,,,some-question5 -Some Question 6,Text,,2014-1-1,some-question6 -Some Question 7,Text,,2014-1-1,some-question7 +Some Question 4,Text,,01/01/2014,some-question4 +Some Question 5,Text,,01/20/2014,some-question5 +Some Question 6,Text,,01/01/2014,some-question6 +Some Question 7,Text,,01/01/2014,some-question7 Some Question 8,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,some-question8 -Some Question 9,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,2014-01-01,some-question9 -Some Question 10,Text,,2015-12-01,some-question10 +Some Question 9,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,01/01/2014,some-question9 +Some Question 10,Text,,01/20/2014,some-question10 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq_small.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq_small.csv index 48caac8109a..0eced8a26ec 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq_small.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/faq_small.csv @@ -1,6 +1,6 @@ Title,Body,Files,Created date,Path -Some Question 1,Text,,2014-1-1,some-question1 -Some Question 2,Text,,2014-1-1,some-question2 +Some Question 1,Text,,01/01/2014,some-question1 +Some Question 2,Text,,01/01/2014,some-question2 Some Question 3,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,some-question3 -Some Question 4,Text,,2014-01-01,some-question4 -Some Question 5,Text,,2014-01-01,some-question5 +Some Question 4,Text,,01/01/2014,some-question4 +Some Question 5,Text,,01/01/2014,some-question5 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles.csv new file mode 100644 index 00000000000..a15baa1d6a8 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles.csv @@ -0,0 +1,7 @@ +Prefix,First name,Middle name,Last name,Photo,Title 1,Title 2,Title 3,Address,Phone,Email,Websites title 1,Websites url 1,Websites title 2,Websites url 2,Websites title 3,Websites url 3,Short bio,Created date,Path +Mr.,Homer 1,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson1 +Mr.,Homer 2,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson2 +Mr.,Homer 3,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson3 +Mr.,Homer 4,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson4 +Mr.,Homer 5,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson5 +Mr.,Homer 6,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,01/01/2020,Homer-simpson6 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles_small.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles_small.csv new file mode 100644 index 00000000000..629abda2ac2 --- /dev/null +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/profiles_small.csv @@ -0,0 +1,7 @@ +Prefix,First name,Middle name,Last name,Photo,Title 1,Title 2,Title 3,Address,Phone,Email,Websites title 1,Websites url 1,Websites title 2,Websites url 2,Websites title 3,Websites url 3,Short bio,Created date,Path +Mr.,Homer 1,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson1 +Mr.,Homer 2,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson2 +Mr.,Homer 3,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson3 +Mr.,Homer 4,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson4 +Mr.,Homer 5,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson5 +Mr.,Homer 6,J,Simpson,https://i.picsum.photos/id/57/536/354.jpg,Safety Inspector,Senior Grade,Head of Dept,742 Evergreen Terrace Springfield,555-1234,homer@snpp.com,Homer's website 1,http://www.homersimpson1.com,Homer's website 2,http://www.homersimpson2.com,Homer's website 3,http://www.homersimpson3.com,Father for 3 and married to Marge Simpson,12/31/2020,Homer-simpson6 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software.csv index 23a6aa69811..6e32413bad6 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software.csv @@ -1,11 +1,11 @@ Title,Body,Files,Created date,Path -Test Software 1,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,2014-1-1,software1 -Test Software 2,Text,,2014-1-1,software2 +Test Software 1,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,01/01/2014,software1 +Test Software 2,Text,,01/01/2014,software2 Test Software 3,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,software3 -Test Software 4,Text,,2014-01-01,software4 +Test Software 4,Text,,01/01/2014,software4 Test Software 5,Text,,,software5 -Test Software 6,Text,,2014-1-1,software6 -Test Software 7,Text,,2014-1-1,software7 +Test Software 6,Text,,01/01/2014,software6 +Test Software 7,Text,,01/01/2014,software7 Test Software 8,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,software8 -Test Software 9,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,2014-01-01,software9 -Test Software 10,Text,,2015-12-01,software10 +Test Software 9,Text,https://scholar.harvard.edu/files/bilsi/files/pptexamples.ppt,01/01/2014,software9 +Test Software 10,Text,,01/01/2014,software10 diff --git a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software_small.csv b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software_small.csv index eb516d97b9a..ac8134cd235 100644 --- a/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software_small.csv +++ b/profile/modules/cp/modules/cp_import/tests/modules/cp_import_csv_test/artifacts/software_small.csv @@ -1,6 +1,6 @@ Title,Body,Files,Created date,Path -Test Software 1,Text,,2014-1-1,software1 -Test Software 2,Text,,2014-1-1,software2 +Test Software 1,Text,,01/01/2014,software1 +Test Software 2,Text,,01/01/2014,software2 Test Software 3,Text,https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf,,software3 -Test Software 4,Text,,2014-01-01,software4 -Test Software 5,Text,,2014-01-01,software5 +Test Software 4,Text,,01/01/2014,software4 +Test Software 5,Text,,01/01/2014,software5 diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportFunctionalTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportFunctionalTest.php index 8e686669e28..fddc8e9875b 100644 --- a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportFunctionalTest.php +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportFunctionalTest.php @@ -70,7 +70,7 @@ public function testSoftwareImportForm() { $this->visitViaVsite('cp/content/import/software', $this->group); $this->levels->set('software', AppAccessLevels::PUBLIC)->save(); $session = $this->assertSession(); - // Checks Faq import form opens. + // Checks Software import form opens. $session->pageTextContains('Software'); // Check sample download link. $url = "/test-alias/cp/content/import/software/template"; @@ -82,6 +82,25 @@ public function testSoftwareImportForm() { $this->assertSession()->responseHeaderContains('Content-Description', 'File Download'); } + /** + * Test Profile import form and sample download. + */ + public function testProfilesImportForm() { + $this->visitViaVsite('cp/content/import/profiles', $this->group); + $this->levels->set('software', AppAccessLevels::PUBLIC)->save(); + $session = $this->assertSession(); + // Checks Profile import form opens. + $session->pageTextContains('Person'); + // Check sample download link. + $url = "/test-alias/cp/content/import/profiles/template"; + $session->linkByHrefExists($url); + + // Test sample download link. + $this->drupalGet('test-alias/cp/content/import/profiles/template'); + $this->assertSession()->responseHeaderContains('Content-Type', 'text/csv; charset=utf-8'); + $this->assertSession()->responseHeaderContains('Content-Description', 'File Download'); + } + /** * Test Publication import form. */ diff --git a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php index 18291048246..b5c92ffae61 100644 --- a/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php +++ b/profile/modules/cp/modules/cp_import/tests/src/ExistingSite/CpImportTest.php @@ -86,14 +86,14 @@ public function setUp() { public function testCpImportHelperMediaCreation() { // Test Media creation with File. $url = 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf'; - $media1 = $this->cpImportHelper->getMedia($url, 'faq'); + $media1 = $this->cpImportHelper->getMedia($url, 'faq', 'field_attached_media'); $this->assertInstanceOf(Media::class, $media1); $this->assertEquals('Review_Committee_Report_20181113.pdf', $media1->getName()); $this->markEntityForCleanup($media1); // Test Negative case for Media creation of Oembed type. $url = 'https://www.youtube.com/watch?v=WadTyp3FcgU&t'; - $media2 = $this->cpImportHelper->getMedia($url, 'faq'); + $media2 = $this->cpImportHelper->getMedia($url, 'faq', 'field_attached_media'); $this->assertNull($media2); } @@ -124,7 +124,7 @@ public function testCpImportHelperCsvToArray() { $data = $this->cpImportHelper->csvToArray($filename, 'utf-8'); $this->assertCount(10, $data); $this->assertEquals('Some Question 5', $data[4]['Title']); - $this->assertEquals('2015-12-01', $data[9]['Created date']); + $this->assertEquals('01/20/2014', $data[9]['Created date']); } /** @@ -170,7 +170,7 @@ public function testCpImportFaqHeaderValidation() { 'Title' => 'Test1', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', ]; $message = $instance->validateHeaders($data); $this->assertEmpty($message['@Title']); @@ -181,7 +181,7 @@ public function testCpImportFaqHeaderValidation() { 'Title' => 'Test1', 'Body' => 'Body1', 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateHeaders($data); @@ -201,7 +201,7 @@ public function testCpImportFaqRowValidation() { 'Title' => '', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -213,7 +213,7 @@ public function testCpImportFaqRowValidation() { 'Title' => 'Title1', 'Body' => '', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -225,7 +225,7 @@ public function testCpImportFaqRowValidation() { 'Title' => 'Test1', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -337,7 +337,7 @@ public function testCpImportBlogHeaderValidation() { 'Title' => 'Blog1', 'Body' => 'Blog1 Test Body', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', ]; $message = $instance->validateHeaders($data); $this->assertEmpty($message['@Title']); @@ -348,7 +348,7 @@ public function testCpImportBlogHeaderValidation() { 'Title' => 'Blog2', 'Body' => 'Body2 Test Body', 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateHeaders($data); @@ -368,7 +368,7 @@ public function testCpImportBlogRowValidation() { 'Title' => '', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -380,7 +380,7 @@ public function testCpImportBlogRowValidation() { 'Title' => 'Blog1', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -460,7 +460,7 @@ public function testCpImportSoftwareHeaderValidation() { 'Title' => 'Software1', 'Body' => 'Software1 Test Body', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', ]; $message = $instance->validateHeaders($data); $this->assertEmpty($message['@Title']); @@ -471,13 +471,80 @@ public function testCpImportSoftwareHeaderValidation() { 'Title' => 'Software1', 'Body' => 'Body2 Test Body', 'Files' => 'https://www.harvard.edu/sites/default/files/content/Review_Committee_Report_20181113.pdf', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateHeaders($data); $this->assertEmpty($message); } + /** + * Tests CpImport Profiles header validations. + */ + public function testCpImportProfilesHeaderValidation() { + /** @var \Drupal\cp_import\AppImportFactory $appImportFactory */ + $appImportFactory = $this->container->get('app_import_factory'); + $instance = $appImportFactory->create('os_profiles_import'); + + // Test header errors. + $data[0] = [ + 'First Name' => '', + 'Last Name' => '', + 'Photo' => 'https://i.picsum.photos/id/57/536/354.jpg', + 'Email' => 'test@test.com', + 'Created date' => '01/01/2015', + ]; + $message = $instance->validateHeaders($data); + $this->assertNotEmpty($message['@First name']); + $this->assertInstanceOf(TranslatableMarkup::class, $message['@Path']); + + // Test No header errors. + $data[0] = [ + 'First name' => 'First name', + 'Last name' => 'Last name', + 'Photo' => 'https://i.picsum.photos/id/57/536/354.jpg', + 'Created date' => '01/01/2015', + 'Email' => 'test@test.com', + 'Path' => 'test1', + ]; + $message = $instance->validateHeaders($data); + $this->assertEmpty($message); + } + + /** + * Tests CpImport Profiles row validations. + */ + public function testCpImportProfilesRowValidation() { + /** @var \Drupal\cp_import\AppImportFactory $appImportFactory */ + $appImportFactory = $this->container->get('app_import_factory'); + $instance = $appImportFactory->create('os_profiles_import'); + + // Test errors. + $data[0] = [ + 'First name' => '', + 'Last name' => '', + 'Photo' => 'https://i.picsum.photos/id/57/536/354.jpg', + 'Created date' => '01/01/2015', + 'Path' => 'test1', + 'Email' => 'test@test.com', + ]; + $message = $instance->validateRows($data); + $this->assertEmpty($message['@date']); + $this->assertInstanceOf(TranslatableMarkup::class, $message['@firstNameRows']); + + // Test no errors in row. + $data[0] = [ + 'First name' => 'First name', + 'Last name' => 'Last name', + 'Photo' => '', + 'Created date' => '01/01/2015', + 'Path' => 'test1', + 'Email' => 'test@test.com', + ]; + $message = $instance->validateRows($data); + $this->assertEmpty($message); + } + /** * Tests CpImport Software row validations. */ @@ -491,7 +558,7 @@ public function testCpImportSoftwareRowValidation() { 'Title' => '', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -503,7 +570,7 @@ public function testCpImportSoftwareRowValidation() { 'Title' => 'Software1', 'Body' => 'Body1', 'Files' => '', - 'Created date' => '2015-01-01', + 'Created date' => '01/01/2015', 'Path' => 'test1', ]; $message = $instance->validateRows($data); @@ -565,4 +632,59 @@ public function testCpImportMigrationSoftware() { $executable->rollback(); } + /** + * Tests Migration/import for os_profiles_import. + * + * @throws \Drupal\migrate\MigrateException + * @throws \Drupal\Component\Plugin\Exception\PluginException + */ + public function testCpImportMigrationProfiles() { + $filename = drupal_get_path('module', 'cp_import_csv_test') . '/artifacts/profiles.csv'; + $this->cpImportHelper->csvToArray($filename, 'utf-8'); + // Replace existing source file. + $path = 'public://importcsv'; + $this->fileSystem->delete($path . '/os_profiles.csv'); + $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY); + file_save_data(file_get_contents($filename), $path . '/os_profiles.csv', FileSystemInterface::EXISTS_REPLACE); + + $storage = $this->entityTypeManager->getStorage('node'); + // Test Negative case. + $node1 = $storage->loadByProperties(['field_first_name' => 'Homer 1']); + $this->assertCount(0, $node1); + $node2 = $storage->loadByProperties(['field_first_name' => 'Homer 2']); + $this->assertCount(0, $node2); + + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = $this->migrationManager->createInstance('os_profiles_import'); + $executable = new MigrateExecutable($migration, new MigrateMessage()); + $executable->import(); + // Test positive case. + $node1 = $storage->loadByProperties(['field_first_name' => 'Homer 1']); + $this->assertCount(1, $node1); + $node2 = $storage->loadByProperties(['field_first_name' => 'Homer 2']); + $this->assertCount(1, $node2); + // Test date is converted from Y-n-j to Y-m-d if node is created. + // successfully it means conversion works. + $node3 = $storage->loadByProperties(['field_first_name' => 'Homer 6']); + $node3 = array_values($node3)[0]; + $created = $node3->getCreatedTime(); + $created_date = date('Y-m-d', $created); + $this->assertEquals('2020-01-01', $created_date); + // Import same content again to check if adding timestamp works. + $filename2 = drupal_get_path('module', 'cp_import_csv_test') . '/artifacts/profiles_small.csv'; + $this->cpImportHelper->csvToArray($filename2, 'utf-8'); + $this->fileSystem->delete($path . '/os_profiles.csv'); + $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY); + file_save_data(file_get_contents($filename2), $path . '/os_profiles.csv', FileSystemInterface::EXISTS_REPLACE); + $migration = $this->migrationManager->createInstance('os_profiles_import'); + $executable = new MigrateExecutable($migration, new MigrateMessage()); + $executable->import(); + // If count is now 2 it means same content is imported again. + $node1 = $storage->loadByProperties(['field_first_name' => 'Homer 1']); + $this->assertCount(2, $node1); + + // Delete all the test data created. + $executable->rollback(); + } + } From bed272771f7b85614a257675d51428d2ec4b4a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Tue, 3 Mar 2020 17:09:08 +0100 Subject: [PATCH 20/58] Issue #12689 - Do update core 8.8 with composer and update lock file --- composer.json | 19 +- composer.lock | 1820 +++++++++++++++++++++++++++++-------------------- 2 files changed, 1072 insertions(+), 767 deletions(-) diff --git a/composer.json b/composer.json index 0baa7861fde..16f450eb151 100644 --- a/composer.json +++ b/composer.json @@ -155,6 +155,7 @@ ], "require": { + "php": ">=7.3", "ext-json": "*", "ckeditor/colorbutton": "^4.11", "ckeditor/colordialog": "^4.12", @@ -163,9 +164,7 @@ "ckeditor/mathjax": "^4.11", "ckeditor/pagebreak": "^4.11", "ckeditor/panelbutton": "^4.11", - "composer/installers": "^1.2", "cweagans/composer-patches": "^1.6", - "doctrine/lexer": "dev-master", "drupal-composer/drupal-scaffold": "^2.6", "drupal/admin_toolbar": "2.0", "drupal/advancedqueue": "^1.0@beta", @@ -185,7 +184,8 @@ "drupal/config_sync": "^2.0@alpha", "drupal/console": "^1.0.2", "drupal/context": "^4.0@beta", - "drupal/core": "^8.7.11", + "drupal/core-recommended": "^8.8", + "drupal/core-dev": "^8.8", "drupal/crop": "^2.0", "drupal/date_recur": "^2.0", "drupal/date_recur_modular": "^1.0@alpha", @@ -257,7 +257,6 @@ "twbs/bootstrap-sass": "^3.3.7", "twig/extensions": "^1.5", "vlucas/phpdotenv": "^2.4", - "webflo/drupal-core-require-dev": "^8.7.11", "webflo/drupal-finder": "^1.0.0", "webmozart/path-util": "^2.3", "zaporylie/composer-drupal-optimizations": "^1.0" @@ -359,18 +358,6 @@ ] }, "patches": { - "drupal/core": { - "Make sure TestSitePath exist before creating .htkey": "https://www.drupal.org/files/issues/2246725-24.patch", - "Views Date Filter Datetime Granularity Option": "https://www.drupal.org/files/issues/2018-12-11/views_date_filter_granularity_2868014-60.patch", - "Add paging info to rest request": "https://www.drupal.org/files/issues/2018-06-30/2982729-viewsRestInfo.patch", - "Getlabel() on null layout builder.": "https://www.drupal.org/files/issues/2018-07-16/2985882-entityfield-2.patch", - "'view_path' is set to /views/ajax after second ajax request": "https://www.drupal.org/files/issues/2018-03-14/drupal-views_path_ajax-2866386-10.patch", - "Image styles fails with absolute path": "https://www.drupal.org/files/issues/image_styles-2754273-7.patch", - "Allow Redirectresponse to override ?destination": "https://www.drupal.org/files/issues/2950883-2.patch", - "User context missing when using toUrl in some circumstances": "https://www.drupal.org/files/issues/2019-05-22/3056234-test-fix-4.patch", - "null route object in big_pipe requests after 8.7.8 upgrade": "https://www.drupal.org/files/issues/2019-10-24/3089913-2.patch", - "Contextual links double trigger": "https://www.drupal.org/files/issues/2019-11-15/drupal-contextual_links_double_trigger-2834346-19.patch" - }, "drupal/group_purl": { "Don't attempt to redirect to subdomains by default": "https://www.drupal.org/files/issues/2019-03-05/group_purl.3036879-4.subdomain_disable.patch", "Page not found error if the request path contains the group prefix": "https://www.drupal.org/files/issues/2020-01-21/3107728-2.patch" diff --git a/composer.lock b/composer.lock index 9d819a61b5e..26ac47f9717 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "de50866308c4b1d37c2547413dee3192", + "content-hash": "f544b2dda0ae0b490fcffe137c83d67e", "packages": [ { "name": "academicpuma/citeproc-php", @@ -297,9 +297,9 @@ "authors": [ { "name": "Nils Werner", - "role": "Developer", "email": "nils.werner@audiolabs-erlangen.de", - "homepage": "http://www.audiolabs-erlangen.de" + "homepage": "http://www.audiolabs-erlangen.de", + "role": "Developer" } ], "description": "Bibtex parser for PHP 5.3", @@ -770,18 +770,154 @@ "homepage": "http://jquery.com", "time": "2018-03-04T13:23:48+00:00" }, + { + "name": "composer/ca-bundle", + "version": "1.2.6", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2020-01-13T10:02:55+00:00" + }, + { + "name": "composer/composer", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/1291a16ce3f48bfdeca39d64fca4875098af4d7b", + "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "composer/semver": "^1.0", + "composer/spdx-licenses": "^1.2", + "composer/xdebug-handler": "^1.1", + "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0" + }, + "conflict": { + "symfony/console": "2.8.38" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7", + "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "time": "2020-02-04T11:58:49+00:00" + }, { "name": "composer/installers", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b" + "reference": "141b272484481432cda342727a427dc1e206bfa0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/cfcca6b1b60bc4974324efb5783c13dca6932b5b", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b", + "url": "https://api.github.com/repos/composer/installers/zipball/141b272484481432cda342727a427dc1e206bfa0", + "reference": "141b272484481432cda342727a427dc1e206bfa0", "shasum": "" }, "require": { @@ -837,6 +973,7 @@ "RadPHP", "SMF", "Thelia", + "Whmcs", "WolfCMS", "agl", "aimeos", @@ -859,6 +996,7 @@ "installer", "itop", "joomla", + "known", "kohana", "laravel", "lavalite", @@ -888,7 +1026,7 @@ "zend", "zikula" ], - "time": "2018-08-27T06:10:37+00:00" + "time": "2019-08-12T15:00:31+00:00" }, { "name": "composer/semver", @@ -952,6 +1090,110 @@ ], "time": "2019-03-19T17:25:45+00:00" }, + { + "name": "composer/spdx-licenses", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "time": "2020-02-14T07:44:31+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2020-03-01T12:26:26+00:00" + }, { "name": "consolidation/annotated-command", "version": "2.12.0", @@ -2014,30 +2256,30 @@ }, { "name": "doctrine/annotations", - "version": "v1.8.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^7.1" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { @@ -2050,10 +2292,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -2062,6 +2300,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -2078,42 +2320,37 @@ "docblock", "parser" ], - "time": "2019-10-01T18:55:10+00:00" + "time": "2017-02-24T16:22:25+00:00" }, { "name": "doctrine/cache", - "version": "1.10.0", + "version": "v1.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62" + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62", - "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62", + "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", "shasum": "" }, "require": { - "php": "~7.1" + "php": "~5.5|~7.0" }, "conflict": { "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "alcaeus/mongo-php-adapter": "^1.1", - "doctrine/coding-standard": "^6.0", - "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^7.0", - "predis/predis": "~1.0" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -2126,10 +2363,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -2138,6 +2371,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -2147,53 +2384,44 @@ "email": "schmittjoh@gmail.com" } ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", "keywords": [ - "abstraction", - "apcu", "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" + "caching" ], - "time": "2019-11-29T15:36:20+00:00" + "time": "2017-07-22T12:49:21+00:00" }, { "name": "doctrine/collections", - "version": "1.6.4", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7" + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", - "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^5.6 || ^7.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan-shim": "^0.9.2", - "phpunit/phpunit": "^7.0", - "vimeo/psalm": "^3.2.2" + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { - "psr-4": { - "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2201,10 +2429,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -2213,6 +2437,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -2222,53 +2450,44 @@ "email": "schmittjoh@gmail.com" } ], - "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", - "homepage": "https://www.doctrine-project.org/projects/collections.html", + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", "keywords": [ "array", "collections", - "iterators", - "php" + "iterator" ], - "time": "2019-11-13T13:07:11+00:00" + "time": "2017-01-03T10:49:41+00:00" }, { "name": "doctrine/common", - "version": "v2.11.0", + "version": "v2.7.3", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff" + "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff", - "reference": "b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff", + "url": "https://api.github.com/repos/doctrine/common/zipball/4acb8f89626baafede6ee5475bc5844096eba8a9", + "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", - "doctrine/cache": "^1.0", - "doctrine/collections": "^1.0", - "doctrine/event-manager": "^1.0", - "doctrine/inflector": "^1.0", - "doctrine/lexer": "^1.0", - "doctrine/persistence": "^1.1", - "doctrine/reflection": "^1.0", - "php": "^7.1" + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": "~5.6|~7.0" }, "require-dev": { - "doctrine/coding-standard": "^1.0", - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "^3.0", - "symfony/phpunit-bridge": "^4.0.5" + "phpunit/phpunit": "^5.4.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.11.x-dev" + "dev-master": "2.7.x-dev" } }, "autoload": { @@ -2281,10 +2500,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -2293,80 +2508,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, persistence interfaces, proxies, event system and much more.", - "homepage": "https://www.doctrine-project.org/projects/common.html", - "keywords": [ - "common", - "doctrine", - "php" - ], - "time": "2019-09-10T10:10:14+00:00" - }, - { - "name": "doctrine/event-manager", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/event-manager.git", - "reference": "629572819973f13486371cb611386eb17851e85c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", - "reference": "629572819973f13486371cb611386eb17851e85c", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "conflict": { - "doctrine/common": "<2.9@dev" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -2374,39 +2519,35 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" } ], - "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", - "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", "keywords": [ - "event", - "event dispatcher", - "event manager", - "event system", - "events" + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" ], - "time": "2019-11-10T09:48:07+00:00" + "time": "2017-07-22T08:35:12+00:00" }, { "name": "doctrine/inflector", - "version": "1.3.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.2" @@ -2414,7 +2555,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -2427,10 +2568,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -2439,6 +2576,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -2456,7 +2597,7 @@ "singularize", "string" ], - "time": "2019-10-30T19:59:35+00:00" + "time": "2017-07-22T12:18:28+00:00" }, { "name": "doctrine/instantiator", @@ -2485,206 +2626,54 @@ "phpunit/phpunit": "^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2019-10-21T16:45:58+00:00" - }, - { - "name": "doctrine/lexer", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "shasum": "" - }, - "require": { - "php": "^7.2" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "time": "2019-10-30T14:39:59+00:00" - }, - { - "name": "doctrine/persistence", - "version": "1.3.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/persistence.git", - "reference": "99b196bbd4715a94fa100fac664a351ffa46d6a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/99b196bbd4715a94fa100fac664a351ffa46d6a5", - "reference": "99b196bbd4715a94fa100fac664a351ffa46d6a5", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.0", - "doctrine/cache": "^1.0", - "doctrine/collections": "^1.0", - "doctrine/event-manager": "^1.0", - "doctrine/reflection": "^1.0", - "php": "^7.1" - }, - "conflict": { - "doctrine/common": "<2.10@dev" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common", - "Doctrine\\Persistence\\": "lib/Doctrine/Persistence" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" } ], - "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", - "homepage": "https://doctrine-project.org/projects/persistence.html", + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ - "mapper", - "object", - "odm", - "orm", - "persistence" + "constructor", + "instantiate" ], - "time": "2019-12-13T10:43:02+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { - "name": "doctrine/reflection", - "version": "v1.0.0", + "name": "doctrine/lexer", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/doctrine/reflection.git", - "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6" + "url": "https://github.com/doctrine/lexer.git", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/reflection/zipball/02538d3f95e88eb397a5f86274deb2c6175c2ab6", - "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", - "ext-tokenizer": "*", - "php": "^7.1" + "php": ">=5.3.2" }, "require-dev": { - "doctrine/coding-standard": "^4.0", - "doctrine/common": "^2.8", - "phpstan/phpstan": "^0.9.2", - "phpstan/phpstan-phpunit": "^0.9.4", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "^3.0" + "phpunit/phpunit": "^4.5" }, "type": "library", "extra": { @@ -2694,7 +2683,7 @@ }, "autoload": { "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -2706,33 +2695,25 @@ "name": "Roman Borschel", "email": "roman@code-factory.org" }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" } ], - "description": "Doctrine Reflection component", - "homepage": "https://www.doctrine-project.org/projects/reflection.html", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ - "reflection" + "annotations", + "docblock", + "lexer", + "parser", + "php" ], - "time": "2018-06-14T14:45:07+00:00" + "time": "2019-06-08T11:03:04+00:00" }, { "name": "drupal-composer/drupal-scaffold", @@ -4634,23 +4615,23 @@ }, { "name": "drupal/core", - "version": "8.7.11", + "version": "8.8.2", "source": { "type": "git", "url": "https://github.com/drupal/core.git", - "reference": "a691876294fadc2795a8add96359b5ffc109d7f2" + "reference": "f997857003276c2ae6d27db30f0eab9c7dd10e62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core/zipball/a691876294fadc2795a8add96359b5ffc109d7f2", - "reference": "a691876294fadc2795a8add96359b5ffc109d7f2", + "url": "https://api.github.com/repos/drupal/core/zipball/f997857003276c2ae6d27db30f0eab9c7dd10e62", + "reference": "f997857003276c2ae6d27db30f0eab9c7dd10e62", "shasum": "" }, "require": { "asm89/stack-cors": "^1.1", "composer/semver": "^1.0", - "doctrine/annotations": "^1.2", - "doctrine/common": "^2.5", + "doctrine/annotations": "^1.4", + "doctrine/common": "^2.7", "easyrdf/easyrdf": "^0.9", "egulias/email-validator": "^2.0", "ext-date": "*", @@ -4666,11 +4647,10 @@ "ext-spl": "*", "ext-tokenizer": "*", "ext-xml": "*", - "guzzlehttp/guzzle": "^6.2.1", + "guzzlehttp/guzzle": "^6.3", "masterminds/html5": "^2.1", - "paragonie/random_compat": "^1.0|^2.0|^9.99.99", "pear/archive_tar": "^1.4.9", - "php": "^5.5.9|>=7.0.8", + "php": ">=7.0.8", "stack/builder": "^1.0", "symfony-cmf/routing": "^1.4", "symfony/class-loader": "~3.4.0", @@ -4688,13 +4668,13 @@ "symfony/validator": "~3.4.0", "symfony/yaml": "~3.4.5", "twig/twig": "^1.38.2", - "typo3/phar-stream-wrapper": "^2.1.1", - "zendframework/zend-diactoros": "^1.1", - "zendframework/zend-feed": "^2.4" + "typo3/phar-stream-wrapper": "^3.1.3", + "zendframework/zend-diactoros": "^1.8", + "zendframework/zend-feed": "^2.12" }, "conflict": { - "drush/drush": "<8.1.10", - "symfony/dom-crawler": ">=4" + "drupal/pathauto": "<1.6", + "drush/drush": "<8.1.10" }, "replace": { "drupal/action": "self.version", @@ -4710,6 +4690,7 @@ "drupal/book": "self.version", "drupal/breakpoint": "self.version", "drupal/ckeditor": "self.version", + "drupal/claro": "self.version", "drupal/classy": "self.version", "drupal/color": "self.version", "drupal/comment": "self.version", @@ -4729,6 +4710,7 @@ "drupal/core-discovery": "self.version", "drupal/core-event-dispatcher": "self.version", "drupal/core-file-cache": "self.version", + "drupal/core-file-security": "self.version", "drupal/core-filesystem": "self.version", "drupal/core-gettext": "self.version", "drupal/core-graph": "self.version", @@ -4756,6 +4738,7 @@ "drupal/forum": "self.version", "drupal/hal": "self.version", "drupal/help": "self.version", + "drupal/help_topics": "self.version", "drupal/history": "self.version", "drupal/image": "self.version", "drupal/inline_form_errors": "self.version", @@ -4778,6 +4761,7 @@ "drupal/options": "self.version", "drupal/page_cache": "self.version", "drupal/path": "self.version", + "drupal/path_alias": "self.version", "drupal/quickedit": "self.version", "drupal/rdf": "self.version", "drupal/responsive_image": "self.version", @@ -4806,64 +4790,34 @@ "drupal/workflows": "self.version", "drupal/workspaces": "self.version" }, - "require-dev": { - "behat/mink": "1.7.x-dev", - "behat/mink-goutte-driver": "^1.2", - "behat/mink-selenium2-driver": "1.3.x-dev", - "drupal/coder": "^8.3.1", - "jcalderonzumba/gastonjs": "^1.0.2", - "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", - "justinrainbow/json-schema": "^5.2", - "mikey179/vfsstream": "^1.2", - "phpspec/prophecy": "^1.7", - "phpunit/phpunit": "^4.8.35 || ^6.5", - "symfony/css-selector": "^3.4.0", - "symfony/debug": "^3.4.0", - "symfony/phpunit-bridge": "^3.4.3" - }, "type": "drupal-core", "extra": { - "merge-plugin": { - "require": [ - "core/lib/Drupal/Component/Annotation/composer.json", - "core/lib/Drupal/Component/Assertion/composer.json", - "core/lib/Drupal/Component/Bridge/composer.json", - "core/lib/Drupal/Component/ClassFinder/composer.json", - "core/lib/Drupal/Component/Datetime/composer.json", - "core/lib/Drupal/Component/DependencyInjection/composer.json", - "core/lib/Drupal/Component/Diff/composer.json", - "core/lib/Drupal/Component/Discovery/composer.json", - "core/lib/Drupal/Component/EventDispatcher/composer.json", - "core/lib/Drupal/Component/FileCache/composer.json", - "core/lib/Drupal/Component/FileSystem/composer.json", - "core/lib/Drupal/Component/Gettext/composer.json", - "core/lib/Drupal/Component/Graph/composer.json", - "core/lib/Drupal/Component/HttpFoundation/composer.json", - "core/lib/Drupal/Component/PhpStorage/composer.json", - "core/lib/Drupal/Component/Plugin/composer.json", - "core/lib/Drupal/Component/ProxyBuilder/composer.json", - "core/lib/Drupal/Component/Render/composer.json", - "core/lib/Drupal/Component/Serialization/composer.json", - "core/lib/Drupal/Component/Transliteration/composer.json", - "core/lib/Drupal/Component/Utility/composer.json", - "core/lib/Drupal/Component/Uuid/composer.json", - "core/lib/Drupal/Component/Version/composer.json" - ], - "recurse": false, - "replace": false, - "merge-extra": false - }, - "patches_applied": { - "Make sure TestSitePath exist before creating .htkey": "https://www.drupal.org/files/issues/2246725-24.patch", - "Views Date Filter Datetime Granularity Option": "https://www.drupal.org/files/issues/2018-12-11/views_date_filter_granularity_2868014-60.patch", - "Add paging info to rest request": "https://www.drupal.org/files/issues/2018-06-30/2982729-viewsRestInfo.patch", - "Getlabel() on null layout builder.": "https://www.drupal.org/files/issues/2018-07-16/2985882-entityfield-2.patch", - "'view_path' is set to /views/ajax after second ajax request": "https://www.drupal.org/files/issues/2018-03-14/drupal-views_path_ajax-2866386-10.patch", - "Image styles fails with absolute path": "https://www.drupal.org/files/issues/image_styles-2754273-7.patch", - "Allow Redirectresponse to override ?destination": "https://www.drupal.org/files/issues/2950883-2.patch", - "User context missing when using toUrl in some circumstances": "https://www.drupal.org/files/issues/2019-05-22/3056234-test-fix-4.patch", - "null route object in big_pipe requests after 8.7.8 upgrade": "https://www.drupal.org/files/issues/2019-10-24/3089913-2.patch", - "Contextual links double trigger": "https://www.drupal.org/files/issues/2019-11-15/drupal-contextual_links_double_trigger-2834346-19.patch" + "drupal-scaffold": { + "file-mapping": { + "[project-root]/.editorconfig": "assets/scaffold/files/editorconfig", + "[project-root]/.gitattributes": "assets/scaffold/files/gitattributes", + "[web-root]/.csslintrc": "assets/scaffold/files/csslintrc", + "[web-root]/.eslintignore": "assets/scaffold/files/eslintignore", + "[web-root]/.eslintrc.json": "assets/scaffold/files/eslintrc.json", + "[web-root]/.ht.router.php": "assets/scaffold/files/ht.router.php", + "[web-root]/.htaccess": "assets/scaffold/files/htaccess", + "[web-root]/example.gitignore": "assets/scaffold/files/example.gitignore", + "[web-root]/index.php": "assets/scaffold/files/index.php", + "[web-root]/INSTALL.txt": "assets/scaffold/files/drupal.INSTALL.txt", + "[web-root]/README.txt": "assets/scaffold/files/drupal.README.txt", + "[web-root]/robots.txt": "assets/scaffold/files/robots.txt", + "[web-root]/update.php": "assets/scaffold/files/update.php", + "[web-root]/web.config": "assets/scaffold/files/web.config", + "[web-root]/sites/README.txt": "assets/scaffold/files/sites.README.txt", + "[web-root]/sites/development.services.yml": "assets/scaffold/files/development.services.yml", + "[web-root]/sites/example.settings.local.php": "assets/scaffold/files/example.settings.local.php", + "[web-root]/sites/example.sites.php": "assets/scaffold/files/example.sites.php", + "[web-root]/sites/default/default.services.yml": "assets/scaffold/files/default.services.yml", + "[web-root]/sites/default/default.settings.php": "assets/scaffold/files/default.settings.php", + "[web-root]/modules/README.txt": "assets/scaffold/files/modules.README.txt", + "[web-root]/profiles/README.txt": "assets/scaffold/files/profiles.README.txt", + "[web-root]/themes/README.txt": "assets/scaffold/files/themes.README.txt" + } } }, "autoload": { @@ -4887,7 +4841,132 @@ "GPL-2.0-or-later" ], "description": "Drupal is an open source content management platform powering millions of websites and applications.", - "time": "2019-12-18T08:55:29+00:00" + "time": "2020-02-01T19:51:15+00:00" + }, + { + "name": "drupal/core-dev", + "version": "8.8.2", + "source": { + "type": "git", + "url": "https://github.com/drupal/core-dev.git", + "reference": "2dffabdcee78b36d513978424ac220da1fe2e11f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/drupal/core-dev/zipball/2dffabdcee78b36d513978424ac220da1fe2e11f", + "reference": "2dffabdcee78b36d513978424ac220da1fe2e11f", + "shasum": "" + }, + "require": { + "behat/mink": "1.8.0 | 1.7.1.1 | 1.7.x-dev", + "behat/mink-goutte-driver": "^1.2", + "behat/mink-selenium2-driver": "1.4.0 | 1.3.1.1 | 1.3.x-dev", + "composer/composer": "^1.9.1", + "drupal/coder": "^8.3.2", + "jcalderonzumba/gastonjs": "^1.0.2", + "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", + "justinrainbow/json-schema": "^5.2", + "mikey179/vfsstream": "^1.6.8", + "phpspec/prophecy": "^1.7", + "phpunit/phpunit": "^6.5 || ^7", + "symfony/browser-kit": "^3.4.0", + "symfony/css-selector": "^3.4.0", + "symfony/debug": "^3.4.0", + "symfony/filesystem": "~3.4.0", + "symfony/finder": "~3.4.0", + "symfony/lock": "~3.4.0", + "symfony/phpunit-bridge": "^3.4.3" + }, + "conflict": { + "webflo/drupal-core-require-dev": "*" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.", + "time": "2019-11-05T11:06:10+00:00" + }, + { + "name": "drupal/core-recommended", + "version": "8.8.2", + "source": { + "type": "git", + "url": "https://github.com/drupal/core-recommended.git", + "reference": "67ed5b68da2784ead5a55330c6c0fde6bb3cb9f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/drupal/core-recommended/zipball/67ed5b68da2784ead5a55330c6c0fde6bb3cb9f3", + "reference": "67ed5b68da2784ead5a55330c6c0fde6bb3cb9f3", + "shasum": "" + }, + "require": { + "asm89/stack-cors": "1.2.0", + "composer/installers": "v1.7.0", + "composer/semver": "1.5.0", + "doctrine/annotations": "v1.4.0", + "doctrine/cache": "v1.6.2", + "doctrine/collections": "v1.4.0", + "doctrine/common": "v2.7.3", + "doctrine/inflector": "v1.2.0", + "doctrine/lexer": "1.0.2", + "drupal/core": "8.8.2", + "easyrdf/easyrdf": "0.9.1", + "egulias/email-validator": "2.1.11", + "guzzlehttp/guzzle": "6.3.3", + "guzzlehttp/promises": "v1.3.1", + "guzzlehttp/psr7": "1.6.1", + "masterminds/html5": "2.3.0", + "paragonie/random_compat": "v9.99.99", + "pear/archive_tar": "1.4.9", + "pear/console_getopt": "v1.4.2", + "pear/pear-core-minimal": "v1.10.9", + "pear/pear_exception": "v1.0.0", + "psr/container": "1.0.0", + "psr/http-message": "1.0.1", + "psr/log": "1.1.0", + "ralouphie/getallheaders": "3.0.3", + "stack/builder": "v1.0.5", + "symfony-cmf/routing": "1.4.1", + "symfony/class-loader": "v3.4.35", + "symfony/console": "v3.4.35", + "symfony/debug": "v3.4.35", + "symfony/dependency-injection": "v3.4.35", + "symfony/event-dispatcher": "v3.4.35", + "symfony/http-foundation": "v3.4.35", + "symfony/http-kernel": "v3.4.35", + "symfony/polyfill-ctype": "v1.12.0", + "symfony/polyfill-iconv": "v1.12.0", + "symfony/polyfill-mbstring": "v1.12.0", + "symfony/polyfill-php56": "v1.12.0", + "symfony/polyfill-php70": "v1.12.0", + "symfony/polyfill-util": "v1.12.0", + "symfony/process": "v3.4.35", + "symfony/psr-http-message-bridge": "v1.1.2", + "symfony/routing": "v3.4.35", + "symfony/serializer": "v3.4.35", + "symfony/translation": "v3.4.35", + "symfony/validator": "v3.4.35", + "symfony/yaml": "v3.4.35", + "twig/twig": "v1.42.3", + "typo3/phar-stream-wrapper": "v3.1.3", + "zendframework/zend-diactoros": "1.8.7", + "zendframework/zend-escaper": "2.6.1", + "zendframework/zend-feed": "2.12.0", + "zendframework/zend-stdlib": "3.2.1" + }, + "conflict": { + "webflo/drupal-core-strict": "*" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Locked core dependencies; require this project INSTEAD OF drupal/core.", + "time": "2020-02-01T19:51:15+00:00" }, { "name": "drupal/courier", @@ -5592,6 +5671,10 @@ "GPL-2.0-or-later" ], "authors": [ + { + "name": "Berdir", + "homepage": "https://www.drupal.org/user/214652" + }, { "name": "Frans", "homepage": "https://www.drupal.org/user/514222" @@ -5608,7 +5691,7 @@ "description": "Adds a Entity Reference field type with revision support.", "homepage": "https://www.drupal.org/project/entity_reference_revisions", "support": { - "source": "http://cgit.drupalcode.org/entity_reference_revisions" + "source": "https://git.drupalcode.org/project/entity_reference_revisions" } }, { @@ -6376,10 +6459,18 @@ "name": "amyvs", "homepage": "https://www.drupal.org/user/3181721" }, + { + "name": "aprice42", + "homepage": "https://www.drupal.org/user/369147" + }, { "name": "gcb", "homepage": "https://www.drupal.org/user/1682976" }, + { + "name": "julia.leah.ford", + "homepage": "https://www.drupal.org/user/3590443" + }, { "name": "levelos", "homepage": "https://www.drupal.org/user/54135" @@ -6412,7 +6503,7 @@ "description": "Mailchimp is an integration with the Mailchimp Mass email tool.", "homepage": "http://drupal.org/project/mailchimp", "support": { - "source": "http://cgit.drupalcode.org/mailchimp" + "source": "https://git.drupalcode.org/project/mailchimp" } }, { @@ -7191,7 +7282,7 @@ "description": "Allows users to redirect from old URLs to new URLs.", "homepage": "https://www.drupal.org/project/redirect", "support": { - "source": "http://cgit.drupalcode.org/redirect" + "source": "https://git.drupalcode.org/project/redirect" } }, { @@ -8565,7 +8656,7 @@ "description": "Provides an accordion views display plugin.", "homepage": "https://www.drupal.org/project/views_accordion", "support": { - "source": "http://cgit.drupalcode.org/views_accordion", + "source": "https://git.drupalcode.org/project/views_accordion", "issues": "https://www.drupal.org/project/issues/views_accordion" } }, @@ -8613,7 +8704,7 @@ "description": "Provides advanced route customisation for Views.", "homepage": "https://www.drupal.org/project/views_advanced_routing", "support": { - "source": "http://cgit.drupalcode.org/views_advanced_routing" + "source": "https://git.drupalcode.org/project/views_advanced_routing" } }, { @@ -8679,6 +8770,10 @@ "GPL-2.0-or-later" ], "authors": [ + { + "name": "Bobík", + "homepage": "https://www.drupal.org/user/123612" + }, { "name": "Remon", "homepage": "https://www.drupal.org/user/143827" @@ -8691,7 +8786,7 @@ "description": "A pager which allows an infinite scroll effect for views.", "homepage": "https://www.drupal.org/project/views_infinite_scroll", "support": { - "source": "http://cgit.drupalcode.org/views_infinite_scroll" + "source": "https://git.drupalcode.org/project/views_infinite_scroll" } }, { @@ -9332,46 +9427,44 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.0", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "dbc2bc3a293ed6b1ae08a3651e2bfd213d19b6a5" + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/dbc2bc3a293ed6b1ae08a3651e2bfd213d19b6a5", - "reference": "dbc2bc3a293ed6b1ae08a3651e2bfd213d19b6a5", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", "shasum": "" }, "require": { - "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", + "guzzlehttp/psr7": "^1.4", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" + "psr/log": "^1.0" }, "suggest": { - "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5-dev" + "dev-master": "6.3-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -9395,7 +9488,7 @@ "rest", "web service" ], - "time": "2019-12-07T18:20:45+00:00" + "time": "2018-04-22T15:46:56+00:00" }, { "name": "guzzlehttp/promises", @@ -10257,33 +10350,31 @@ }, { "name": "masterminds/html5", - "version": "2.7.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "104443ad663d15981225f99532ba73c2f1d6b6f2" + "reference": "2c37c6c520b995b761674de3be8455a381679067" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/104443ad663d15981225f99532ba73c2f1d6b6f2", - "reference": "104443ad663d15981225f99532ba73c2f1d6b6f2", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/2c37c6c520b995b761674de3be8455a381679067", + "reference": "2c37c6c520b995b761674de3be8455a381679067", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-dom": "*", "ext-libxml": "*", "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35", + "phpunit/phpunit": "4.*", "sami/sami": "~2.0", "satooshi/php-coveralls": "1.0.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.2-dev" } }, "autoload": { @@ -10300,13 +10391,13 @@ "name": "Matt Butcher", "email": "technosophos@gmail.com" }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, { "name": "Asmir Mustafic", "email": "goetas@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" } ], "description": "An HTML5 parser and serializer.", @@ -10320,7 +10411,7 @@ "serializer", "xml" ], - "time": "2019-07-25T07:03:26+00:00" + "time": "2017-09-04T12:26:28+00:00" }, { "name": "mikey179/vfsstream", @@ -10777,16 +10868,16 @@ }, { "name": "pear/console_getopt", - "version": "v1.4.3", + "version": "v1.4.2", "source": { "type": "git", "url": "https://github.com/pear/Console_Getopt.git", - "reference": "a41f8d3e668987609178c7c4a9fe48fecac53fa0" + "reference": "6c77aeb625b32bd752e89ee17972d103588b90c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/Console_Getopt/zipball/a41f8d3e668987609178c7c4a9fe48fecac53fa0", - "reference": "a41f8d3e668987609178c7c4a9fe48fecac53fa0", + "url": "https://api.github.com/repos/pear/Console_Getopt/zipball/6c77aeb625b32bd752e89ee17972d103588b90c0", + "reference": "6c77aeb625b32bd752e89ee17972d103588b90c0", "shasum": "" }, "type": "library", @@ -10803,6 +10894,11 @@ "BSD-2-Clause" ], "authors": [ + { + "name": "Greg Beaver", + "email": "cellog@php.net", + "role": "Helper" + }, { "name": "Andrei Zmievski", "email": "andrei@php.net", @@ -10812,28 +10908,23 @@ "name": "Stig Bakken", "email": "stig@php.net", "role": "Developer" - }, - { - "name": "Greg Beaver", - "email": "cellog@php.net", - "role": "Helper" } ], "description": "More info available on: http://pear.php.net/package/Console_Getopt", - "time": "2019-11-20T18:27:48+00:00" + "time": "2019-02-06T16:52:33+00:00" }, { "name": "pear/pear-core-minimal", - "version": "v1.10.10", + "version": "v1.10.9", "source": { "type": "git", "url": "https://github.com/pear/pear-core-minimal.git", - "reference": "625a3c429d9b2c1546438679074cac1b089116a7" + "reference": "742be8dd68c746a01e4b0a422258e9c9cae1c37f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/625a3c429d9b2c1546438679074cac1b089116a7", - "reference": "625a3c429d9b2c1546438679074cac1b089116a7", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/742be8dd68c746a01e4b0a422258e9c9cae1c37f", + "reference": "742be8dd68c746a01e4b0a422258e9c9cae1c37f", "shasum": "" }, "require": { @@ -10859,25 +10950,25 @@ "authors": [ { "name": "Christian Weiske", - "role": "Lead", - "email": "cweiske@php.net" + "email": "cweiske@php.net", + "role": "Lead" } ], "description": "Minimal set of PEAR core files to be used as composer dependency", - "time": "2019-11-19T19:00:24+00:00" + "time": "2019-03-13T18:15:44+00:00" }, { "name": "pear/pear_exception", - "version": "v1.0.1", + "version": "v1.0.0", "source": { "type": "git", "url": "https://github.com/pear/PEAR_Exception.git", - "reference": "dbb42a5a0e45f3adcf99babfb2a1ba77b8ac36a7" + "reference": "8c18719fdae000b690e3912be401c76e406dd13b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/dbb42a5a0e45f3adcf99babfb2a1ba77b8ac36a7", - "reference": "dbb42a5a0e45f3adcf99babfb2a1ba77b8ac36a7", + "url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/8c18719fdae000b690e3912be401c76e406dd13b", + "reference": "8c18719fdae000b690e3912be401c76e406dd13b", "shasum": "" }, "require": { @@ -10893,9 +10984,9 @@ } }, "autoload": { - "classmap": [ - "PEAR/" - ] + "psr-0": { + "PEAR": "" + } }, "notification-url": "https://packagist.org/downloads/", "include-path": [ @@ -10919,7 +11010,7 @@ "keywords": [ "exception" ], - "time": "2019-12-10T10:24:42+00:00" + "time": "2015-02-10T20:07:52+00:00" }, { "name": "phar-io/manifest", @@ -11777,16 +11868,16 @@ }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { @@ -11795,7 +11886,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -11820,7 +11911,7 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "time": "2018-11-20T15:27:04+00:00" }, { "name": "psy/psysh", @@ -12695,52 +12786,145 @@ "email": "sebastian@phpunit.de" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "time": "2019-10-24T14:27:39+00:00" }, { - "name": "sebastian/version", - "version": "2.0.1", + "name": "seld/phar-utils", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=5.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Seld\\PharUtils\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "time": "2020-02-14T15:25:33+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -13047,27 +13231,25 @@ }, { "name": "symfony/browser-kit", - "version": "v4.4.1", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "e19e465c055137938afd40cfddd687e7511bbbf0" + "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/e19e465c055137938afd40cfddd687e7511bbbf0", - "reference": "e19e465c055137938afd40cfddd687e7511bbbf0", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", + "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/dom-crawler": "^3.4|^4.0|^5.0" + "php": "^5.5.9|>=7.0.8", + "symfony/dom-crawler": "~2.8|~3.0|~4.0" }, "require-dev": { - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/http-client": "^4.3|^5.0", - "symfony/mime": "^4.3|^5.0", - "symfony/process": "^3.4|^4.0|^5.0" + "symfony/css-selector": "~2.8|~3.0|~4.0", + "symfony/process": "~2.8|~3.0|~4.0" }, "suggest": { "symfony/process": "" @@ -13075,7 +13257,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -13102,11 +13284,11 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2019-10-28T20:30:34+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/class-loader", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", @@ -13162,16 +13344,16 @@ }, { "name": "symfony/config", - "version": "v3.4.27", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "177a276c01575253c95cefe0866e3d1b57637fe0" + "reference": "03328d6e172ec7384341c622d4c28d350040d021" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/177a276c01575253c95cefe0866e3d1b57637fe0", - "reference": "177a276c01575253c95cefe0866e3d1b57637fe0", + "url": "https://api.github.com/repos/symfony/config/zipball/03328d6e172ec7384341c622d4c28d350040d021", + "reference": "03328d6e172ec7384341c622d4c28d350040d021", "shasum": "" }, "require": { @@ -13222,20 +13404,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:06:07+00:00" + "time": "2020-02-03T08:11:57+00:00" }, { "name": "symfony/console", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586" + "reference": "17b154f932c5874cdbda6d05796b6490eec9f9f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ee23b3b659b06c622f2bd2492a229e416eb4586", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586", + "url": "https://api.github.com/repos/symfony/console/zipball/17b154f932c5874cdbda6d05796b6490eec9f9f7", + "reference": "17b154f932c5874cdbda6d05796b6490eec9f9f7", "shasum": "" }, "require": { @@ -13294,20 +13476,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-12-01T10:04:45+00:00" + "time": "2019-11-13T07:12:39+00:00" }, { "name": "symfony/css-selector", - "version": "v3.4.36", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f" + "reference": "ee9b946e7223b11257329a054c64396b19d619e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f819f71ae3ba6f396b4c015bd5895de7d2f1f85f", - "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ee9b946e7223b11257329a054c64396b19d619e1", + "reference": "ee9b946e7223b11257329a054c64396b19d619e1", "shasum": "" }, "require": { @@ -13347,11 +13529,11 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2019-10-01T11:57:37+00:00" + "time": "2020-02-04T08:04:52+00:00" }, { "name": "symfony/debug", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -13407,16 +13589,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2" + "reference": "0ea4d39ca82409a25a43b61ce828048a90000920" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0d201916bfb3af939fec3c0c8815ea16c60ac1a2", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0ea4d39ca82409a25a43b61ce828048a90000920", + "reference": "0ea4d39ca82409a25a43b61ce828048a90000920", "shasum": "" }, "require": { @@ -13474,20 +13656,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2019-12-01T08:33:36+00:00" + "time": "2019-11-08T16:18:30+00:00" }, { "name": "symfony/dom-crawler", - "version": "v3.4.36", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3" + "reference": "5ea08fead7392bc5bfe83fb8a289ac9b72cb689e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3", - "reference": "6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5ea08fead7392bc5bfe83fb8a289ac9b72cb689e", + "reference": "5ea08fead7392bc5bfe83fb8a289ac9b72cb689e", "shasum": "" }, "require": { @@ -13531,11 +13713,11 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" + "time": "2020-02-26T17:12:32+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -13598,16 +13780,16 @@ }, { "name": "symfony/filesystem", - "version": "v3.4.35", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516" + "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516", - "reference": "00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0a0d3b4bda11aa3a0464531c40e681e184e75628", + "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628", "shasum": "" }, "require": { @@ -13644,20 +13826,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-08-20T13:31:17+00:00" + "time": "2020-01-17T08:50:08+00:00" }, { "name": "symfony/finder", - "version": "v3.4.36", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf" + "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/290ae21279b37bfd287cdcce640d51204e84afdf", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf", + "url": "https://api.github.com/repos/symfony/finder/zipball/5ec813ccafa8164ef21757e8c725d3a57da59200", + "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200", "shasum": "" }, "require": { @@ -13693,20 +13875,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-11-17T21:55:15+00:00" + "time": "2020-02-14T07:34:21+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593" + "reference": "9e4b3ac8fa3348b4811674d23de32d201de225ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d2d0cfe8e319d9df44c4cca570710fcf221d4593", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9e4b3ac8fa3348b4811674d23de32d201de225ce", + "reference": "9e4b3ac8fa3348b4811674d23de32d201de225ce", "shasum": "" }, "require": { @@ -13747,20 +13929,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-11-28T12:52:59+00:00" + "time": "2019-11-11T12:53:10+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7" + "reference": "e1764b3de00ec5636dd03d02fd44bcb1147d70d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c42c8339acb28cfff0fb1786948db4d23d609ff7", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e1764b3de00ec5636dd03d02fd44bcb1147d70d9", + "reference": "e1764b3de00ec5636dd03d02fd44bcb1147d70d9", "shasum": "" }, "require": { @@ -13837,27 +14019,89 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2019-12-01T13:50:37+00:00" + "time": "2019-11-13T08:44:50+00:00" + }, + { + "name": "symfony/lock", + "version": "v3.4.38", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "c8fe2c2ea8177852825a0b92d0897114feda0695" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/c8fe2c2ea8177852825a0b92d0897114feda0695", + "reference": "c8fe2c2ea8177852825a0b92d0897114feda0695", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/polyfill-php70": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ], + "time": "2020-02-04T08:04:52+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v3.4.36", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "cbea8818e9f34e4e9d780bd22bdda21b57d4d5c7" + "reference": "c02893ae43532b46a4f0e0f207d088b939f278d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/cbea8818e9f34e4e9d780bd22bdda21b57d4d5c7", - "reference": "cbea8818e9f34e4e9d780bd22bdda21b57d4d5c7", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/c02893ae43532b46a4f0e0f207d088b939f278d9", + "reference": "c02893ae43532b46a4f0e0f207d088b939f278d9", "shasum": "" }, "require": { "php": ">=5.3.3" }, "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0" }, "suggest": { "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" @@ -13902,20 +14146,20 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2019-09-30T20:33:19+00:00" + "time": "2020-02-21T08:01:47+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { @@ -13927,7 +14171,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -13960,20 +14204,20 @@ "polyfill", "portable" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36" + "reference": "685968b11e61a347c18bf25db32effa478be610f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/a019efccc03f1a335af6b4f20c30f5ea8060be36", - "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/685968b11e61a347c18bf25db32effa478be610f", + "reference": "685968b11e61a347c18bf25db32effa478be610f", "shasum": "" }, "require": { @@ -13985,7 +14229,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -14019,20 +14263,20 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", "shasum": "" }, "require": { @@ -14044,7 +14288,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -14078,20 +14322,20 @@ "portable", "shim" ], - "time": "2019-11-27T14:18:11+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-php56", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "53dd1cdf3cb986893ccf2b96665b25b3abb384f4" + "reference": "0e3b212e96a51338639d8ce175c046d7729c3403" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/53dd1cdf3cb986893ccf2b96665b25b3abb384f4", - "reference": "53dd1cdf3cb986893ccf2b96665b25b3abb384f4", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/0e3b212e96a51338639d8ce175c046d7729c3403", + "reference": "0e3b212e96a51338639d8ce175c046d7729c3403", "shasum": "" }, "require": { @@ -14101,7 +14345,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -14134,20 +14378,20 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "af23c7bb26a73b850840823662dda371484926c4" + "reference": "54b4c428a0054e254223797d2713c31e08610831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", - "reference": "af23c7bb26a73b850840823662dda371484926c4", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/54b4c428a0054e254223797d2713c31e08610831", + "reference": "54b4c428a0054e254223797d2713c31e08610831", "shasum": "" }, "require": { @@ -14157,7 +14401,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -14193,20 +14437,20 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.11.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c" + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", "shasum": "" }, "require": { @@ -14215,7 +14459,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -14248,20 +14492,20 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { "name": "symfony/polyfill-util", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-util.git", - "reference": "964a67f293b66b95883a5ed918a65354fcd2258f" + "reference": "4317de1386717b4c22caed7725350a8887ab205c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/964a67f293b66b95883a5ed918a65354fcd2258f", - "reference": "964a67f293b66b95883a5ed918a65354fcd2258f", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/4317de1386717b4c22caed7725350a8887ab205c", + "reference": "4317de1386717b4c22caed7725350a8887ab205c", "shasum": "" }, "require": { @@ -14270,7 +14514,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -14300,20 +14544,20 @@ "polyfill", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/process", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "9a4545c01e1e4f473492bd52b71e574dcc401ca2" + "reference": "c19da50bc3e8fa7d60628fdb4ab5d67de534cf3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/9a4545c01e1e4f473492bd52b71e574dcc401ca2", - "reference": "9a4545c01e1e4f473492bd52b71e574dcc401ca2", + "url": "https://api.github.com/repos/symfony/process/zipball/c19da50bc3e8fa7d60628fdb4ab5d67de534cf3e", + "reference": "c19da50bc3e8fa7d60628fdb4ab5d67de534cf3e", "shasum": "" }, "require": { @@ -14349,31 +14593,29 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-11-28T10:05:51+00:00" + "time": "2019-10-24T15:33:53+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v1.2.0", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad" + "reference": "a33352af16f78a5ff4f9d90811536abf210df12b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", - "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/a33352af16f78a5ff4f9d90811536abf210df12b", + "reference": "a33352af16f78a5ff4f9d90811536abf210df12b", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^5.3.3 || ^7.0", "psr/http-message": "^1.0", - "symfony/http-foundation": "^3.4 || ^4.0" + "symfony/http-foundation": "^2.3.42 || ^3.4 || ^4.0" }, "require-dev": { - "nyholm/psr7": "^1.1", - "symfony/phpunit-bridge": "^3.4.20 || ^4.0", - "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + "symfony/phpunit-bridge": "^3.4 || ^4.0" }, "suggest": { "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" @@ -14381,7 +14623,7 @@ "type": "symfony-bridge", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -14414,20 +14656,20 @@ "psr-17", "psr-7" ], - "time": "2019-03-11T18:22:33+00:00" + "time": "2019-04-03T17:09:40+00:00" }, { "name": "symfony/routing", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a" + "reference": "afc10b9c6b5196e0fecbc3bd373c7b4482e5b6b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/b689ccd48e234ea404806d94b07eeb45f9f6f06a", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a", + "url": "https://api.github.com/repos/symfony/routing/zipball/afc10b9c6b5196e0fecbc3bd373c7b4482e5b6b5", + "reference": "afc10b9c6b5196e0fecbc3bd373c7b4482e5b6b5", "shasum": "" }, "require": { @@ -14490,20 +14732,20 @@ "uri", "url" ], - "time": "2019-12-01T08:33:36+00:00" + "time": "2019-11-08T17:25:00+00:00" }, { "name": "symfony/serializer", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "05a1125ff3fdd10a68a2857a5d1d4a1ceb93ba42" + "reference": "9d14f7ff2c585a8a9f6f980253066285ddc2f675" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/05a1125ff3fdd10a68a2857a5d1d4a1ceb93ba42", - "reference": "05a1125ff3fdd10a68a2857a5d1d4a1ceb93ba42", + "url": "https://api.github.com/repos/symfony/serializer/zipball/9d14f7ff2c585a8a9f6f980253066285ddc2f675", + "reference": "9d14f7ff2c585a8a9f6f980253066285ddc2f675", "shasum": "" }, "require": { @@ -14569,20 +14811,20 @@ ], "description": "Symfony Serializer Component", "homepage": "https://symfony.com", - "time": "2019-11-25T16:36:22+00:00" + "time": "2019-11-12T17:51:12+00:00" }, { "name": "symfony/translation", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "0be25347c4a8695d9423fe897f4c774f46e97b51" + "reference": "2031c895bc97ac1787d418d90bd1ed7d299f2772" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/0be25347c4a8695d9423fe897f4c774f46e97b51", - "reference": "0be25347c4a8695d9423fe897f4c774f46e97b51", + "url": "https://api.github.com/repos/symfony/translation/zipball/2031c895bc97ac1787d418d90bd1ed7d299f2772", + "reference": "2031c895bc97ac1787d418d90bd1ed7d299f2772", "shasum": "" }, "require": { @@ -14639,20 +14881,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2019-11-23T20:30:33+00:00" + "time": "2019-10-30T12:43:22+00:00" }, { "name": "symfony/validator", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "55e329a518baa3b169b7d278620ae2cd76005188" + "reference": "b11f45742c5c9a228cedc46b70c6317780a1ac80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/55e329a518baa3b169b7d278620ae2cd76005188", - "reference": "55e329a518baa3b169b7d278620ae2cd76005188", + "url": "https://api.github.com/repos/symfony/validator/zipball/b11f45742c5c9a228cedc46b70c6317780a1ac80", + "reference": "b11f45742c5c9a228cedc46b70c6317780a1ac80", "shasum": "" }, "require": { @@ -14725,20 +14967,20 @@ ], "description": "Symfony Validator Component", "homepage": "https://symfony.com", - "time": "2019-11-29T19:07:18+00:00" + "time": "2019-11-05T22:03:38+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.2.8", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce" + "reference": "2572839911702b0405479410ea7a1334bfab0b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce", - "reference": "3c4084cb1537c0e2ad41aad622bbf55a44a5c9ce", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2572839911702b0405479410ea7a1334bfab0b96", + "reference": "2572839911702b0405479410ea7a1334bfab0b96", "shasum": "" }, "require": { @@ -14752,9 +14994,9 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "twig/twig": "~1.34|~2.4" + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -14767,7 +15009,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -14801,11 +15043,11 @@ "debug", "dump" ], - "time": "2019-05-01T12:55:36+00:00" + "time": "2020-02-24T13:10:00+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.36", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", @@ -14939,8 +15181,8 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", @@ -15093,16 +15335,16 @@ }, { "name": "twig/twig", - "version": "v1.42.4", + "version": "v1.42.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152" + "reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/e587180584c3d2d6cb864a0454e777bb6dcb6152", - "reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/201baee843e0ffe8b0b956f336dd42b2a92fae4e", + "reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e", "shasum": "" }, "require": { @@ -15155,35 +15397,39 @@ "keywords": [ "templating" ], - "time": "2019-11-11T16:49:32+00:00" + "time": "2019-08-24T12:51:03+00:00" }, { "name": "typo3/phar-stream-wrapper", - "version": "v2.1.3", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/TYPO3/phar-stream-wrapper.git", - "reference": "e8a656d72028b97ab9f61ed993734f3cded02eeb" + "reference": "586ff60beea128e069a5dc271d3d8133a9bc460a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/TYPO3/phar-stream-wrapper/zipball/e8a656d72028b97ab9f61ed993734f3cded02eeb", - "reference": "e8a656d72028b97ab9f61ed993734f3cded02eeb", + "url": "https://api.github.com/repos/TYPO3/phar-stream-wrapper/zipball/586ff60beea128e069a5dc271d3d8133a9bc460a", + "reference": "586ff60beea128e069a5dc271d3d8133a9bc460a", "shasum": "" }, "require": { - "brumann/polyfill-unserialize": "^1.0", "ext-json": "*", - "php": "^5.3.3|^7.0" + "php": "^7.0" }, "require-dev": { "ext-xdebug": "*", - "phpunit/phpunit": "^4.8.36" + "phpunit/phpunit": "^6.5" }, "suggest": { "ext-fileinfo": "For PHP builtin file type guessing, otherwise uses internal processing" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "v3.x-dev" + } + }, "autoload": { "psr-4": { "TYPO3\\PharStreamWrapper\\": "src/" @@ -15201,7 +15447,7 @@ "security", "stream-wrapper" ], - "time": "2019-10-18T11:59:10+00:00" + "time": "2019-10-18T11:57:16+00:00" }, { "name": "vlucas/phpdotenv", @@ -15254,45 +15500,6 @@ ], "time": "2019-01-29T11:11:52+00:00" }, - { - "name": "webflo/drupal-core-require-dev", - "version": "8.7.11", - "source": { - "type": "git", - "url": "https://github.com/webflo/drupal-core-require-dev.git", - "reference": "0230f86e2813d8a44ffa3e497036d6990591c61f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webflo/drupal-core-require-dev/zipball/0230f86e2813d8a44ffa3e497036d6990591c61f", - "reference": "0230f86e2813d8a44ffa3e497036d6990591c61f", - "shasum": "" - }, - "require": { - "behat/mink": "1.7.x-dev", - "behat/mink-goutte-driver": "^1.2", - "behat/mink-selenium2-driver": "1.3.x-dev", - "drupal/coder": "^8.3.1", - "drupal/core": "8.7.11", - "jcalderonzumba/gastonjs": "^1.0.2", - "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", - "justinrainbow/json-schema": "^5.2", - "mikey179/vfsstream": "^1.2", - "phpspec/prophecy": "^1.7", - "phpunit/phpunit": "^4.8.35 || ^6.5", - "symfony/css-selector": "^3.4.0", - "symfony/debug": "^3.4.0", - "symfony/phpunit-bridge": "^3.4.3" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-or-later" - ], - "description": "require-dev dependencies from drupal/core", - "abandoned": "drupal/core-dev", - "time": "2019-12-18T19:01:45+00:00" - }, { "name": "webflo/drupal-finder", "version": "1.1.0", @@ -15689,6 +15896,42 @@ } ], "packages-dev": [ + { + "name": "brumann/polyfill-unserialize", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/dbrumann/polyfill-unserialize.git", + "reference": "8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dbrumann/polyfill-unserialize/zipball/8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008", + "reference": "8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brumann\\Polyfill\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Denis Brumann", + "email": "denis.brumann@sensiolabs.de" + } + ], + "description": "Backports unserialize options introduced in PHP 7.0 to older PHP versions.", + "time": "2019-07-14T23:16:24+00:00" + }, { "name": "dmore/chrome-mink-driver", "version": "2.7.0", @@ -15737,6 +15980,81 @@ "description": "Mink driver for controlling chrome without selenium", "time": "2019-03-30T09:22:58+00:00" }, + { + "name": "doctrine/reflection", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/reflection.git", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^4.0", + "doctrine/common": "^2.8", + "phpstan/phpstan": "^0.9.2", + "phpstan/phpstan-phpunit": "^0.9.4", + "phpunit/phpunit": "^7.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Doctrine Reflection component", + "homepage": "https://www.doctrine-project.org/projects/reflection.html", + "keywords": [ + "reflection" + ], + "time": "2018-06-14T14:45:07+00:00" + }, { "name": "drupal/devel", "version": "1.2.0", @@ -16692,7 +17010,6 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "doctrine/lexer": 20, "drupal/advancedqueue": 10, "drupal/bibcite": 20, "drupal/bibcite_pubmed": 20, @@ -16711,6 +17028,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { + "php": ">=7.3", "ext-json": "*" }, "platform-dev": [] From 6699c2dff39c8748ec76dbd425848e9ff0333e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Tue, 3 Mar 2020 17:09:29 +0100 Subject: [PATCH 21/58] Issue #12689 - Fix drupal install path alias module --- config/sync/core.extension.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index 910e390acef..a437adc0a4d 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -146,6 +146,7 @@ module: pagebreak: 0 panelbutton: 0 path: 0 + path_alias: 0 purl: 0 quickedit: 0 rdf: 0 From 2724b594bbf0eb2bcf4d6bf616ea3eec444ed533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Tue, 3 Mar 2020 17:50:34 +0100 Subject: [PATCH 22/58] Issue #12689 - Fix phpunit version to 7.x --- composer.lock | 395 ++++++++++++++++++++------------------------------ 1 file changed, 155 insertions(+), 240 deletions(-) diff --git a/composer.lock b/composer.lock index 26ac47f9717..2010e16dbc5 100644 --- a/composer.lock +++ b/composer.lock @@ -542,42 +542,6 @@ ], "time": "2018-10-10T12:39:06+00:00" }, - { - "name": "brumann/polyfill-unserialize", - "version": "v1.0.4", - "source": { - "type": "git", - "url": "https://github.com/dbrumann/polyfill-unserialize.git", - "reference": "8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dbrumann/polyfill-unserialize/zipball/8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008", - "reference": "8ed1cd343ddc134a7ef649aca0aa0fe2a1b45008", - "shasum": "" - }, - "require": { - "php": "^5.3|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Brumann\\Polyfill\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Denis Brumann", - "email": "denis.brumann@sensiolabs.de" - } - ], - "description": "Backports unserialize options introduced in PHP 7.0 to older PHP versions.", - "time": "2019-07-14T23:16:24+00:00" - }, { "name": "caseyamcl/php-marc21", "version": "v1.0", @@ -10531,16 +10495,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { @@ -10575,7 +10539,7 @@ "object", "object graph" ], - "time": "2019-12-15T19:12:40+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "nikic/php-parser", @@ -11014,22 +10978,22 @@ }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -11065,20 +11029,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -11112,7 +11076,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "php-ds/php-ds", @@ -11215,40 +11179,38 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.2", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -11259,33 +11221,36 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-09-12T14:27:41+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.2", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "ext-tokenizer": "^7.2", + "mockery/mockery": "~1" }, "type": "library", "extra": { @@ -11309,28 +11274,28 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "time": "2020-02-18T18:59:58+00:00" }, { "name": "phpspec/prophecy", - "version": "1.10.0", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d638ebbb58daba25a6a0dc7969e1358a0e3c6682", - "reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { "phpspec/phpspec": "^2.5 || ^3.2", @@ -11372,44 +11337,44 @@ "spy", "stub" ], - "time": "2019-12-17T16:54:23+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1 || ^4.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -11435,29 +11400,32 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2018-10-31T16:06:48+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -11472,7 +11440,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -11482,7 +11450,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -11527,28 +11495,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -11563,7 +11531,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -11572,33 +11540,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -11621,57 +11589,57 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.14", + "version": "7.5.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0", "sebastian/version": "^2.0.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" + "phpunit/phpunit-mock-objects": "*" }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -11679,7 +11647,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.5-dev" } }, "autoload": { @@ -11705,67 +11673,7 @@ "testing", "xunit" ], - "time": "2019-02-01T05:22:47+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5.11" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" + "time": "2020-01-08T08:45:45+00:00" }, { "name": "psr/container", @@ -12321,30 +12229,30 @@ }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -12381,32 +12289,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -12431,34 +12340,40 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -12483,7 +12398,7 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", @@ -12750,25 +12665,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -12788,7 +12703,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" }, { "name": "sebastian/version", @@ -15539,16 +15454,16 @@ }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", "shasum": "" }, "require": { @@ -15583,7 +15498,7 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "time": "2020-02-14T12:15:55+00:00" }, { "name": "webmozart/path-util", From 99d9ddc9da8cfd8b6b03a4f2ebeab4ba0c47f926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 11:35:30 +0100 Subject: [PATCH 23/58] Issue #12689 - Composer order fix --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 16f450eb151..429bb877621 100644 --- a/composer.json +++ b/composer.json @@ -184,8 +184,8 @@ "drupal/config_sync": "^2.0@alpha", "drupal/console": "^1.0.2", "drupal/context": "^4.0@beta", - "drupal/core-recommended": "^8.8", "drupal/core-dev": "^8.8", + "drupal/core-recommended": "^8.8", "drupal/crop": "^2.0", "drupal/date_recur": "^2.0", "drupal/date_recur_modular": "^1.0@alpha", From f03b6ba3d4075f98bb8272ba7e992bfdbb0e00c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 11:45:16 +0100 Subject: [PATCH 24/58] Issue #12689 - Update Drupa 8.8 default settings for travis --- .travis/config/default.settings.php | 176 +++++++++++++--------------- 1 file changed, 80 insertions(+), 96 deletions(-) diff --git a/.travis/config/default.settings.php b/.travis/config/default.settings.php index 241fdd5eb87..e6d3ec4cf81 100644 --- a/.travis/config/default.settings.php +++ b/.travis/config/default.settings.php @@ -76,7 +76,7 @@ * specific needs. * * @code - * $databases['default']['default'] = array ( + * $databases['default']['default'] = [ * 'database' => 'databasename', * 'username' => 'sqlusername', * 'password' => 'sqlpassword', @@ -85,7 +85,7 @@ * 'driver' => 'mysql', * 'prefix' => '', * 'collation' => 'utf8mb4_general_ci', - * ); + * ]; * @endcode */ $databases = []; @@ -156,13 +156,13 @@ * The 'default' element is mandatory and holds the prefix for any tables * not specified elsewhere in the array. Example: * @code - * 'prefix' => array( + * 'prefix' => [ * 'default' => 'main_', * 'users' => 'shared_', * 'sessions' => 'shared_', * 'role' => 'shared_', * 'authmap' => 'shared_', - * ), + * ], * @endcode * You can also use a reference to a schema/database as a prefix. This may be * useful if your Drupal installation exists in a schema that is not the default @@ -170,13 +170,13 @@ * time. * Example: * @code - * 'prefix' => array( + * 'prefix' => [ * 'default' => 'main.', * 'users' => 'shared.', * 'sessions' => 'shared.', * 'role' => 'shared.', * 'authmap' => 'shared.', - * ); + * ]; * @endcode * NOTE: MySQL and SQLite's definition of a schema is a database. * @@ -185,14 +185,14 @@ * example, to enable MySQL SELECT queries to exceed the max_join_size system * variable, and to reduce the database connection timeout to 5 seconds: * @code - * $databases['default']['default'] = array( - * 'init_commands' => array( + * $databases['default']['default'] = [ + * 'init_commands' => [ * 'big_selects' => 'SET SQL_BIG_SELECTS=1', - * ), - * 'pdo' => array( + * ], + * 'pdo' => [ * PDO::ATTR_TIMEOUT => 5, - * ), - * ); + * ], + * ]; * @endcode * * WARNING: The above defaults are designed for database portability. Changing @@ -207,51 +207,37 @@ * * Sample Database configuration format for PostgreSQL (pgsql): * @code - * $databases['default']['default'] = array( + * $databases['default']['default'] = [ * 'driver' => 'pgsql', * 'database' => 'databasename', * 'username' => 'sqlusername', * 'password' => 'sqlpassword', * 'host' => 'localhost', * 'prefix' => '', - * ); + * ]; * @endcode * * Sample Database configuration format for SQLite (sqlite): * @code - * $databases['default']['default'] = array( + * $databases['default']['default'] = [ * 'driver' => 'sqlite', * 'database' => '/path/to/databasefilename', - * ); + * ]; * @endcode */ /** * Location of the site configuration files. * - * The $config_directories array specifies the location of file system - * directories used for configuration data. On install, the "sync" directory is - * created. This is used for configuration imports. The "active" directory is - * not created by default since the default storage for active configuration is - * the database rather than the file system. (This can be changed. See "Active - * configuration settings" below). + * The $settings['config_sync_directory'] specifies the location of file system + * directory used for syncing configuration data. On install, the directory is + * created. This is used for configuration imports. * - * The default location for the "sync" directory is inside a randomly-named - * directory in the public files path. The setting below allows you to override - * the "sync" location. - * - * If you use files for the "active" configuration, you can tell the - * Configuration system where this directory is located by adding an entry with - * array key CONFIG_ACTIVE_DIRECTORY. - * - * Example: - * @code - * $config_directories = array( - * CONFIG_SYNC_DIRECTORY => '/directory/outside/webroot', - * ); - * @endcode + * The default location for this directory is inside a randomly-named + * directory in the public files path. The setting below allows you to set + * its location. */ -$config_directories = []; +# $settings['config_sync_directory'] = '/directory/outside/webroot'; /** * Settings: @@ -342,11 +328,10 @@ * configuration requires the IP addresses of all remote proxies to be * specified in $settings['reverse_proxy_addresses'] to work correctly. * - * Enable this setting to get Drupal to determine the client IP from - * the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set). - * If you are unsure about this setting, do not have a reverse proxy, - * or Drupal operates in a shared hosting environment, this setting - * should remain commented out. + * Enable this setting to get Drupal to determine the client IP from the + * X-Forwarded-For header. If you are unsure about this setting, do not have a + * reverse proxy, or Drupal operates in a shared hosting environment, this + * setting should remain commented out. * * In order for this setting to be used you must specify every possible * reverse proxy IP address in $settings['reverse_proxy_addresses']. @@ -365,34 +350,35 @@ # $settings['reverse_proxy_addresses'] = ['a.b.c.d', ...]; /** - * Set this value if your proxy server sends the client IP in a header - * other than X-Forwarded-For. - */ -# $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Proto. - */ -# $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Host. - */ -# $settings['reverse_proxy_host_header'] = 'X_FORWARDED_HOST'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Port. + * Reverse proxy trusted headers. + * + * Sets which headers to trust from your reverse proxy. + * + * Common values are: + * - \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * - \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * + * Note the default value of + * @code + * \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * @endcode + * is not secure by default. The value should be set to only the specific + * headers the reverse proxy uses. For example: + * @code + * \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * @endcode + * This would trust the following headers: + * - X_FORWARDED_FOR + * - X_FORWARDED_HOST + * - X_FORWARDED_PROTO + * - X_FORWARDED_PORT + * + * @see \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * @see \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * @see \Symfony\Component\HttpFoundation\Request::setTrustedProxies */ -# $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT'; +# $settings['reverse_proxy_trusted_headers'] = \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED; -/** - * Set this value if your proxy server sends the client protocol in a header - * other than Forwarded. - */ -# $settings['reverse_proxy_forwarded_header'] = 'FORWARDED'; /** * Page caching: @@ -536,6 +522,19 @@ */ # $settings['file_private_path'] = ''; +/** + * Temporary file path: + * + * A local file system path where temporary files will be stored. This directory + * must be absolute, outside of the Drupal installation directory and not + * accessible over the web. + * + * If this is not set, the default for the operating system will be used. + * + * @see \Drupal\Component\FileSystem\FileSystem::getOsTemporaryDirectory() + */ +# $settings['file_temp_path'] = '/tmp'; + /** * Session write interval: * @@ -596,25 +595,6 @@ # ini_set('pcre.backtrack_limit', 200000); # ini_set('pcre.recursion_limit', 200000); -/** - * Active configuration settings. - * - * By default, the active configuration is stored in the database in the - * {config} table. To use a different storage mechanism for the active - * configuration, do the following prior to installing: - * - Create an "active" directory and declare its path in $config_directories - * as explained under the 'Location of the site configuration files' section - * above in this file. To enhance security, you can declare a path that is - * outside your document root. - * - Override the 'bootstrap_config_storage' setting here. It must be set to a - * callable that returns an object that implements - * \Drupal\Core\Config\StorageInterface. - * - Override the service definition 'config.storage.active'. Put this - * override in a services.yml file in the same directory as settings.php - * (definitions in this file will override service definition defaults). - */ -# $settings['bootstrap_config_storage'] = ['Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage']; - /** * Configuration overrides. * @@ -637,9 +617,7 @@ * configuration values in settings.php will not fire any of the configuration * change events. */ -# $config['system.file']['path']['temporary'] = '/tmp'; # $config['system.site']['name'] = 'My Drupal site'; -# $config['system.theme']['default'] = 'stark'; # $config['user.settings']['anonymous'] = 'Visitor'; /** @@ -705,9 +683,9 @@ * * For example: * @code - * $settings['trusted_host_patterns'] = array( + * $settings['trusted_host_patterns'] = [ * '^www\.example\.com$', - * ); + * ]; * @endcode * will allow the site to only run from www.example.com. * @@ -718,12 +696,12 @@ * * For example: * @code - * $settings['trusted_host_patterns'] = array( + * $settings['trusted_host_patterns'] = [ * '^example\.com$', * '^.+\.example\.com$', * '^example\.org$', * '^.+\.example\.org$', - * ); + * ]; * @endcode * will allow the site to run off of all variants of example.com and * example.org, with all subdomains included. @@ -736,7 +714,7 @@ * with common frontend tools and recursive scanning of directories looking for * extensions. * - * @see file_scan_directory() + * @see \Drupal\Core\File\FileSystemInterface::scanDirectory() * @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() */ $settings['file_scan_ignore_directories'] = [ @@ -754,8 +732,14 @@ */ $settings['entity_update_batch_size'] = 50; -$settings['install_profile'] = 'openscholar'; -$config_directories['sync'] = '../config/sync'; +/** + * Entity update backup. + * + * This is used to inform the entity storage handler that the backup tables as + * well as the original entity type and field storage definitions should be + * retained after a successful entity update process. + */ +$settings['entity_update_backup'] = TRUE; /** * Load local development override configuration, if available. From ac28787fbe2a54290f1f592366189a00c4d042c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 11:55:35 +0100 Subject: [PATCH 25/58] Issue #12689 - Update Drupal 8.8 default settings --- defaults/settings.php | 190 ++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 101 deletions(-) diff --git a/defaults/settings.php b/defaults/settings.php index d1635d03e42..5cf99ad5792 100644 --- a/defaults/settings.php +++ b/defaults/settings.php @@ -76,7 +76,7 @@ * specific needs. * * @code - * $databases['default']['default'] = array ( + * $databases['default']['default'] = [ * 'database' => 'databasename', * 'username' => 'sqlusername', * 'password' => 'sqlpassword', @@ -85,7 +85,7 @@ * 'driver' => 'mysql', * 'prefix' => '', * 'collation' => 'utf8mb4_general_ci', - * ); + * ]; * @endcode */ $databases = []; @@ -156,13 +156,13 @@ * The 'default' element is mandatory and holds the prefix for any tables * not specified elsewhere in the array. Example: * @code - * 'prefix' => array( + * 'prefix' => [ * 'default' => 'main_', * 'users' => 'shared_', * 'sessions' => 'shared_', * 'role' => 'shared_', * 'authmap' => 'shared_', - * ), + * ], * @endcode * You can also use a reference to a schema/database as a prefix. This may be * useful if your Drupal installation exists in a schema that is not the default @@ -170,13 +170,13 @@ * time. * Example: * @code - * 'prefix' => array( + * 'prefix' => [ * 'default' => 'main.', * 'users' => 'shared.', * 'sessions' => 'shared.', * 'role' => 'shared.', * 'authmap' => 'shared.', - * ); + * ]; * @endcode * NOTE: MySQL and SQLite's definition of a schema is a database. * @@ -185,14 +185,14 @@ * example, to enable MySQL SELECT queries to exceed the max_join_size system * variable, and to reduce the database connection timeout to 5 seconds: * @code - * $databases['default']['default'] = array( - * 'init_commands' => array( + * $databases['default']['default'] = [ + * 'init_commands' => [ * 'big_selects' => 'SET SQL_BIG_SELECTS=1', - * ), - * 'pdo' => array( + * ], + * 'pdo' => [ * PDO::ATTR_TIMEOUT => 5, - * ), - * ); + * ], + * ]; * @endcode * * WARNING: The above defaults are designed for database portability. Changing @@ -207,51 +207,37 @@ * * Sample Database configuration format for PostgreSQL (pgsql): * @code - * $databases['default']['default'] = array( + * $databases['default']['default'] = [ * 'driver' => 'pgsql', * 'database' => 'databasename', * 'username' => 'sqlusername', * 'password' => 'sqlpassword', * 'host' => 'localhost', * 'prefix' => '', - * ); + * ]; * @endcode * * Sample Database configuration format for SQLite (sqlite): * @code - * $databases['default']['default'] = array( + * $databases['default']['default'] = [ * 'driver' => 'sqlite', * 'database' => '/path/to/databasefilename', - * ); + * ]; * @endcode */ /** * Location of the site configuration files. * - * The $config_directories array specifies the location of file system - * directories used for configuration data. On install, the "sync" directory is - * created. This is used for configuration imports. The "active" directory is - * not created by default since the default storage for active configuration is - * the database rather than the file system. (This can be changed. See "Active - * configuration settings" below). + * The $settings['config_sync_directory'] specifies the location of file system + * directory used for syncing configuration data. On install, the directory is + * created. This is used for configuration imports. * - * The default location for the "sync" directory is inside a randomly-named - * directory in the public files path. The setting below allows you to override - * the "sync" location. - * - * If you use files for the "active" configuration, you can tell the - * Configuration system where this directory is located by adding an entry with - * array key CONFIG_ACTIVE_DIRECTORY. - * - * Example: - * @code - * $config_directories = array( - * CONFIG_SYNC_DIRECTORY => '/directory/outside/webroot', - * ); - * @endcode + * The default location for this directory is inside a randomly-named + * directory in the public files path. The setting below allows you to set + * its location. */ -$config_directories = []; +# $settings['config_sync_directory'] = '/directory/outside/webroot'; /** * Settings: @@ -342,11 +328,10 @@ * configuration requires the IP addresses of all remote proxies to be * specified in $settings['reverse_proxy_addresses'] to work correctly. * - * Enable this setting to get Drupal to determine the client IP from - * the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set). - * If you are unsure about this setting, do not have a reverse proxy, - * or Drupal operates in a shared hosting environment, this setting - * should remain commented out. + * Enable this setting to get Drupal to determine the client IP from the + * X-Forwarded-For header. If you are unsure about this setting, do not have a + * reverse proxy, or Drupal operates in a shared hosting environment, this + * setting should remain commented out. * * In order for this setting to be used you must specify every possible * reverse proxy IP address in $settings['reverse_proxy_addresses']. @@ -365,34 +350,35 @@ # $settings['reverse_proxy_addresses'] = ['a.b.c.d', ...]; /** - * Set this value if your proxy server sends the client IP in a header - * other than X-Forwarded-For. - */ -# $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Proto. - */ -# $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Host. - */ -# $settings['reverse_proxy_host_header'] = 'X_FORWARDED_HOST'; - -/** - * Set this value if your proxy server sends the client protocol in a header - * other than X-Forwarded-Port. + * Reverse proxy trusted headers. + * + * Sets which headers to trust from your reverse proxy. + * + * Common values are: + * - \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * - \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * + * Note the default value of + * @code + * \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * @endcode + * is not secure by default. The value should be set to only the specific + * headers the reverse proxy uses. For example: + * @code + * \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * @endcode + * This would trust the following headers: + * - X_FORWARDED_FOR + * - X_FORWARDED_HOST + * - X_FORWARDED_PROTO + * - X_FORWARDED_PORT + * + * @see \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL + * @see \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED + * @see \Symfony\Component\HttpFoundation\Request::setTrustedProxies */ -# $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT'; +# $settings['reverse_proxy_trusted_headers'] = \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED; -/** - * Set this value if your proxy server sends the client protocol in a header - * other than Forwarded. - */ -# $settings['reverse_proxy_forwarded_header'] = 'FORWARDED'; /** * Page caching: @@ -536,6 +522,19 @@ */ # $settings['file_private_path'] = ''; +/** + * Temporary file path: + * + * A local file system path where temporary files will be stored. This directory + * must be absolute, outside of the Drupal installation directory and not + * accessible over the web. + * + * If this is not set, the default for the operating system will be used. + * + * @see \Drupal\Component\FileSystem\FileSystem::getOsTemporaryDirectory() + */ +# $settings['file_temp_path'] = '/tmp'; + /** * Session write interval: * @@ -596,25 +595,6 @@ # ini_set('pcre.backtrack_limit', 200000); # ini_set('pcre.recursion_limit', 200000); -/** - * Active configuration settings. - * - * By default, the active configuration is stored in the database in the - * {config} table. To use a different storage mechanism for the active - * configuration, do the following prior to installing: - * - Create an "active" directory and declare its path in $config_directories - * as explained under the 'Location of the site configuration files' section - * above in this file. To enhance security, you can declare a path that is - * outside your document root. - * - Override the 'bootstrap_config_storage' setting here. It must be set to a - * callable that returns an object that implements - * \Drupal\Core\Config\StorageInterface. - * - Override the service definition 'config.storage.active'. Put this - * override in a services.yml file in the same directory as settings.php - * (definitions in this file will override service definition defaults). - */ -# $settings['bootstrap_config_storage'] = ['Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage']; - /** * Configuration overrides. * @@ -637,9 +617,7 @@ * configuration values in settings.php will not fire any of the configuration * change events. */ -# $config['system.file']['path']['temporary'] = '/tmp'; # $config['system.site']['name'] = 'My Drupal site'; -# $config['system.theme']['default'] = 'stark'; # $config['user.settings']['anonymous'] = 'Visitor'; /** @@ -705,9 +683,9 @@ * * For example: * @code - * $settings['trusted_host_patterns'] = array( + * $settings['trusted_host_patterns'] = [ * '^www\.example\.com$', - * ); + * ]; * @endcode * will allow the site to only run from www.example.com. * @@ -718,12 +696,12 @@ * * For example: * @code - * $settings['trusted_host_patterns'] = array( + * $settings['trusted_host_patterns'] = [ * '^example\.com$', * '^.+\.example\.com$', * '^example\.org$', * '^.+\.example\.org$', - * ); + * ]; * @endcode * will allow the site to run off of all variants of example.com and * example.org, with all subdomains included. @@ -736,7 +714,7 @@ * with common frontend tools and recursive scanning of directories looking for * extensions. * - * @see file_scan_directory() + * @see \Drupal\Core\File\FileSystemInterface::scanDirectory() * @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() */ $settings['file_scan_ignore_directories'] = [ @@ -754,10 +732,14 @@ */ $settings['entity_update_batch_size'] = 50; -$config_directories['sync'] = '../config/sync'; - -# Default installation profile. -$settings['install_profile'] = 'openscholar'; +/** + * Entity update backup. + * + * This is used to inform the entity storage handler that the backup tables as + * well as the original entity type and field storage definitions should be + * retained after a successful entity update process. + */ +$settings['entity_update_backup'] = TRUE; /** * Load local development override configuration, if available. @@ -769,6 +751,12 @@ * * Keep this code block at the end of this file to take full effect. */ -if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { - include $app_root . '/' . $site_path . '/settings.local.php'; -} +# +# if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { +# include $app_root . '/' . $site_path . '/settings.local.php'; +# } + +$settings['config_sync_directory'] = '../config/sync'; + +# Default installation profile. +$settings['install_profile'] = 'openscholar'; From 5271297ee94063239f5b4a77cd44fc9f8954e554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 12:01:49 +0100 Subject: [PATCH 26/58] Issue #12689 - Try to fix class loader --- .travis/config/bootstrap.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis/config/bootstrap.php b/.travis/config/bootstrap.php index 8843d6ff7d6..b178d7d0bcf 100644 --- a/.travis/config/bootstrap.php +++ b/.travis/config/bootstrap.php @@ -16,6 +16,7 @@ * * @param string $scan_directory * The directory that should be recursively scanned. + * * @return array * An associative array of extension directories found within the scanned * directory, keyed by extension name. @@ -78,7 +79,7 @@ function drupal_phpunit_contrib_extension_directory_roots($root = NULL) { * @return array * An associative array of extension directories, keyed by their namespace. */ -function drupal_phpunit_get_extension_namespaces($dirs) { +function drupal_phpunit_get_extension_namespaces(array $dirs) { $suite_names = [ 'Unit', 'Kernel', @@ -135,6 +136,7 @@ function drupal_phpunit_populate_class_loader() { $loader = require __DIR__ . '/../../autoload.php'; // Start with classes in known locations. + $loader->add('Drupal\\TestTools', __DIR__); $loader->add('Drupal\\Tests', __DIR__); $loader->add('Drupal\\TestSite', __DIR__); $loader->add('Drupal\\KernelTests', __DIR__); From 477ed13c8c7311139ebeaf28da2d7ebc0f938f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 12:13:20 +0100 Subject: [PATCH 27/58] Issue #12689 - Replace Drupal scaffold with 8.8 version --- composer.json | 15 ++++++++- composer.lock | 93 ++++++++++++++++++++++++++------------------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/composer.json b/composer.json index 429bb877621..d9713d4cb58 100644 --- a/composer.json +++ b/composer.json @@ -165,7 +165,6 @@ "ckeditor/pagebreak": "^4.11", "ckeditor/panelbutton": "^4.11", "cweagans/composer-patches": "^1.6", - "drupal-composer/drupal-scaffold": "^2.6", "drupal/admin_toolbar": "2.0", "drupal/advancedqueue": "^1.0@beta", "drupal/anchor_link": "^2.0", @@ -184,6 +183,7 @@ "drupal/config_sync": "^2.0@alpha", "drupal/console": "^1.0.2", "drupal/context": "^4.0@beta", + "drupal/core-composer-scaffold": "^8.8", "drupal/core-dev": "^8.8", "drupal/core-recommended": "^8.8", "drupal/crop": "^2.0", @@ -349,6 +349,19 @@ "drush/Commands/{$name}": ["type:drupal-drush"] }, "drupal-scaffold": { + "locations": { + "web-root": "web/" + }, + "allowed-packages": [ + "drupal/core" + ], + "file-mapping": { + "[web-root]/.htaccess": { + "mode": "replace", + "path": "web/core/assets/scaffold/files/htaccess", + "overwrite": false + } + }, "initial": { ".editorconfig": "../.editorconfig", ".gitattributes": "../.gitattributes" diff --git a/composer.lock b/composer.lock index 2010e16dbc5..0a434fc1a53 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f544b2dda0ae0b490fcffe137c83d67e", + "content-hash": "a3ea6c1f7067090d428b060ae103b45e", "packages": [ { "name": "academicpuma/citeproc-php", @@ -2679,50 +2679,6 @@ ], "time": "2019-06-08T11:03:04+00:00" }, - { - "name": "drupal-composer/drupal-scaffold", - "version": "2.6.1", - "source": { - "type": "git", - "url": "https://github.com/drupal-composer/drupal-scaffold.git", - "reference": "13c1ffc7dd4925cb03707759128b85c0cd6276f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/drupal-composer/drupal-scaffold/zipball/13c1ffc7dd4925cb03707759128b85c0cd6276f8", - "reference": "13c1ffc7dd4925cb03707759128b85c0cd6276f8", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0.0", - "composer/semver": "^1.4", - "php": "^5.5.9|>=7.0.8" - }, - "require-dev": { - "composer/composer": "dev-master", - "g1a/composer-test-scenarios": "^2.1.0", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2.8" - }, - "type": "composer-plugin", - "extra": { - "class": "DrupalComposer\\DrupalScaffold\\Plugin", - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "DrupalComposer\\DrupalScaffold\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-or-later" - ], - "description": "Composer Plugin for updating the Drupal scaffold files when using drupal/core", - "time": "2019-03-30T10:41:38+00:00" - }, { "name": "drupal/admin_toolbar", "version": "2.0.0", @@ -4807,6 +4763,53 @@ "description": "Drupal is an open source content management platform powering millions of websites and applications.", "time": "2020-02-01T19:51:15+00:00" }, + { + "name": "drupal/core-composer-scaffold", + "version": "8.8.2", + "source": { + "type": "git", + "url": "https://github.com/drupal/core-composer-scaffold.git", + "reference": "dca4b123a638d78bf77719632993e920de6cc426" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/drupal/core-composer-scaffold/zipball/dca4b123a638d78bf77719632993e920de6cc426", + "reference": "dca4b123a638d78bf77719632993e920de6cc426", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": ">=7.0.8" + }, + "conflict": { + "drupal-composer/drupal-scaffold": "*" + }, + "require-dev": { + "composer/composer": "^1.8@stable" + }, + "type": "composer-plugin", + "extra": { + "class": "Drupal\\Composer\\Plugin\\Scaffold\\Plugin", + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Drupal\\Composer\\Plugin\\Scaffold\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "A flexible Composer project scaffold builder.", + "homepage": "https://www.drupal.org/project/drupal", + "keywords": [ + "drupal" + ], + "time": "2019-10-09T02:55:24+00:00" + }, { "name": "drupal/core-dev", "version": "8.8.2", From 6997113794e614125fc5874ef9ed0bc5a1bea7ab Mon Sep 17 00:00:00 2001 From: Ashish Prabhakar Date: Wed, 4 Mar 2020 17:26:23 +0530 Subject: [PATCH 28/58] Issue #12642 - Reduce filter with buckets - Terms (#13117) * Issue #12642 - Reduce filter with buckets - Terms * Issue #12642 - Tests & Error Fixes * Issue #12642 - PR Fixes --- .../os_search/src/OsSearchFacetBuilder.php | 8 +-- .../Plugin/OsWidgets/CurrentSearchWidget.php | 2 +- .../src/Plugin/OsWidgets/FacetWidget.php | 42 ++++++++++-- .../ExistingSiteJavascript/OsSearchJsTest.php | 66 +++++++++++++++++++ .../tests/src/Traits/SearchTestTrait.php | 8 ++- 5 files changed, 111 insertions(+), 15 deletions(-) diff --git a/profile/modules/custom/os_search/src/OsSearchFacetBuilder.php b/profile/modules/custom/os_search/src/OsSearchFacetBuilder.php index 50fda6ae005..9b47346dbb5 100644 --- a/profile/modules/custom/os_search/src/OsSearchFacetBuilder.php +++ b/profile/modules/custom/os_search/src/OsSearchFacetBuilder.php @@ -339,9 +339,9 @@ public function getCurrentSearchSummary($field_id) { $reduced_filter_links[] = $filter; $summary['needed'] = TRUE; $summary['reduced_filter'][$i]['filter'] = $filter; - $summary['reduced_filter'][$i]['label'] = $this->prepareSingleLabel($this->getFieldProcessor($field_id), $field_id, $value); + $summary['reduced_filter'][$i]['label'] = $this->prepareSingleLabel($field_processor, $field_id, $value); $summary['reduced_filter'][$i]['query'] = ($field_processor == 'date') ? $reduced_filter_links : $filters; - $summary['reduced_filter'][$i]['value'] = $value; + $summary['reduced_filter'][$i]['key'] = $value; $i++; } } @@ -424,10 +424,10 @@ public function prepareFacetVocaulbaries(array $buckets, $field_processor = 'tax $entity_storage = $this->entityTypeManager->getStorage($field_processor); foreach ($buckets as $bucket) { $term = $entity_storage->load($bucket['key']); - if ($term) { + if ($term && isset($vocabularies[$term->bundle()])) { $vocab_list[$term->bundle()]['children'][] = $bucket; + $vocab_list[$term->bundle()]['name'] = $vocabularies[$term->bundle()]->get('name'); } - $vocab_list[$term->bundle()]['name'] = $vocabularies[$term->bundle()]->get('name'); } return $vocab_list; } diff --git a/profile/modules/custom/os_search/src/Plugin/OsWidgets/CurrentSearchWidget.php b/profile/modules/custom/os_search/src/Plugin/OsWidgets/CurrentSearchWidget.php index 6439ae859c2..b31b606563b 100644 --- a/profile/modules/custom/os_search/src/Plugin/OsWidgets/CurrentSearchWidget.php +++ b/profile/modules/custom/os_search/src/Plugin/OsWidgets/CurrentSearchWidget.php @@ -126,7 +126,7 @@ public function buildBlock(&$build, $block_content) { $path = Url::fromRoute($route_name, ($reduced_filters + $route_parameters)); $path_string = Link::fromTextAndUrl("(-)", $path)->toString(); - $summary_items[$reduced_filter['value']] = $this->t('@path_string @label', ['@path_string' => $path_string, '@label' => $item_label]); + $summary_items[$reduced_filter['key']] = $this->t('@path_string @label', ['@path_string' => $path_string, '@label' => $item_label]); } } } diff --git a/profile/modules/custom/os_search/src/Plugin/OsWidgets/FacetWidget.php b/profile/modules/custom/os_search/src/Plugin/OsWidgets/FacetWidget.php index f8165f49cbe..c4beb08435a 100644 --- a/profile/modules/custom/os_search/src/Plugin/OsWidgets/FacetWidget.php +++ b/profile/modules/custom/os_search/src/Plugin/OsWidgets/FacetWidget.php @@ -125,19 +125,32 @@ public function buildBlock(&$build, $block_content) { // Get current search summary with (-) link. $reduced_filters = $this->osSearchFacetBuilder->getCurrentSearchSummary($field_id); $build = []; - $build['current_summary'] = $this->renderReducedfilter($reduced_filters, $field_label, $route_name); if ($field_type != 'date') { $buckets = (count($buckets) > 1) ? $buckets : []; } - switch ($field_id) { - case 'custom_taxonomy': - $vocab_list = $this->osSearchFacetBuilder->prepareFacetVocaulbaries($buckets, $field_processor); + switch ($field_processor) { + case 'taxonomy_term': + $total_buckets = []; + + // Embed reduce filter inside buckets for terms. + if ($reduced_filters['needed']) { + $total_buckets = array_merge($reduced_filters['reduced_filter'], $buckets); + } + else { + $total_buckets = $buckets; + } + + $vocab_list = $this->osSearchFacetBuilder->prepareFacetVocaulbaries($total_buckets, $field_processor); + $build['title'] = [ + '#markup' => '

    ' . $this->t('Filter By @field_label', ['@field_label' => $field_label]) . '

    ', + ]; $build[] = $this->renderableTaxonomyArray($vocab_list, $route_name, $field_id, $field_label); break; default: + $build['current_summary'] = $this->renderReducedfilter($reduced_filters, $field_label, $route_name); $build[] = $this->renderableArray($buckets, $route_name, $field_id, $field_label); break; } @@ -189,7 +202,21 @@ private function renderableArray(array $buckets, $route_name, string $field_name $route_parameters['keys'] = $keys; $path = Url::fromRoute($route_name, $route_parameters); - $items[] = Link::fromTextAndUrl($this->t('@label (@count)', ['@label' => $item_label, '@count' => $bucket['doc_count']]), $path)->toString(); + if (isset($bucket['doc_count'])) { + $items[] = Link::fromTextAndUrl($this->t('@label (@count)', ['@label' => $item_label, '@count' => $bucket['doc_count']]), $path)->toString(); + } + else { + $querys = isset($bucket['query']) ? $bucket['query'] : []; + foreach ($querys as $key => $query) { + if ($query == $bucket['filter']) { + unset($querys[$key]); + } + } + + $path = Url::fromRoute($route_name, ['f' => $querys, 'keys' => $keys]); + $path_string = Link::fromTextAndUrl("(-)", $path)->toString(); + $items[] = $this->t('@path_string @label', ['@path_string' => $path_string, '@label' => $item_label]); + } } if ($header) { @@ -234,9 +261,9 @@ private function renderableTaxonomyArray(array $buckets, $route_name, string $fi foreach ($buckets as $term_list) { $vocab_name = $term_list['name']; - $build[] = $this->renderableArray($term_list['children'], $route_name, $field_name, $field_label, $vocab_name); } + if (empty($buckets)) { $build[$field_name]['empty-filter'] = [ '#markup' => '
    ' . $this->t('No filters available') . '
    ', @@ -279,6 +306,7 @@ public function renderReducedfilter(array $reduced_filters = NULL, string $field $summary_items[] = $this->t('@path_string @label', ['@path_string' => $path_string, '@label' => $item_label]); } } + $build['current_summary']['title'] = [ '#markup' => '

    ' . $this->t('Filter By @field_label', ['@field_label' => $field_label]) . '

    ', ]; @@ -286,7 +314,7 @@ public function renderReducedfilter(array $reduced_filters = NULL, string $field '#theme' => 'item_list__search_widget', '#empty' => '', '#list_type' => 'ul', - '#items' => $summary_items, + '#items' => $summary_items ?? [], ]; return $build; } diff --git a/profile/modules/custom/os_search/tests/src/ExistingSiteJavascript/OsSearchJsTest.php b/profile/modules/custom/os_search/tests/src/ExistingSiteJavascript/OsSearchJsTest.php index ebbee084021..e8ba910a54f 100644 --- a/profile/modules/custom/os_search/tests/src/ExistingSiteJavascript/OsSearchJsTest.php +++ b/profile/modules/custom/os_search/tests/src/ExistingSiteJavascript/OsSearchJsTest.php @@ -130,4 +130,70 @@ public function testSearchSortsAsc(): void { } } + /** + * Tests term search facets. + */ + public function testTermFacets() { + /** @var \Drupal\vsite\Plugin\VsiteContextManagerInterface $vsite_context_manager */ + $vsite_context_manager = $this->container->get('vsite.context_manager'); + // Activate vsite and create a vocabulary. + $vsite_context_manager->activateVsite($this->group); + $vocabulary = $this->createVocabulary(); + $config = $this->container->get('config.factory'); + $config_vocab = $config->getEditable('taxonomy.vocabulary.' . $vocabulary->id()); + $config_vocab->set('allowed_vocabulary_reference_types', ['node:blog'])->save(TRUE); + $web_assert = $this->assertSession(); + + $term1 = $this->createTerm($vocabulary, ['name' => 'Search Test1']); + $term2 = $this->createTerm($vocabulary, ['name' => 'Search Test2']); + $term3 = $this->createTerm($vocabulary, ['name' => 'Search Test3']); + + $this->group->addContent($term1, 'group_entity:taxonomy_term'); + $this->group->addContent($term2, 'group_entity:taxonomy_term'); + $this->group->addContent($term3, 'group_entity:taxonomy_term'); + + $blog = $this->createNode([ + 'type' => 'blog', + 'status' => 1, + 'field_taxonomy_terms' => [ + $term1->id(), + $term2->id(), + $term3->id(), + ], + ]); + $this->group->addContent($blog, 'group_node:blog'); + + $blog = $this->createNode([ + 'type' => 'blog', + 'status' => 1, + 'field_taxonomy_terms' => [ + $term2->id(), + ], + ]); + $this->group->addContent($blog, 'group_node:blog'); + + $task_manager = $this->container->get('search_api.index_task_manager'); + $task_manager->addItemsAll($this->index); + $this->index->indexItems(); + + // Wait is required as Elastic Server + // takes sometime to respond to queries. + $this->getIndexQueryStatus($this->differentiator, 1, 15); + + $this->visitViaVsite("search", $this->group); + $web_assert->statusCodeEquals(200); + $this->assertContains('17 results found', $this->getCurrentPage()->getHtml()); + + $this->visitViaVsite("search?f[0]=custom_taxonomy:{$term2->id()}", $this->group); + $web_assert->statusCodeEquals(200); + $filter_by_taxonomy_links = $this->getSession()->getPage()->findAll('css', '#block-globalfilterbytaxonomy ul li a'); + + $this->assertEquals("(-)", $filter_by_taxonomy_links[0]->getText()); + $this->assertEquals("Search Test1 (1)", $filter_by_taxonomy_links[1]->getText()); + $this->assertEquals("Search Test3 (1)", $filter_by_taxonomy_links[2]->getText()); + + $filter_by_taxonomy_items = $this->getSession()->getPage()->findAll('css', '#block-globalfilterbytaxonomy ul li'); + $this->assertEquals("(-) Search Test2", $filter_by_taxonomy_items[0]->getText()); + } + } diff --git a/profile/modules/custom/os_search/tests/src/Traits/SearchTestTrait.php b/profile/modules/custom/os_search/tests/src/Traits/SearchTestTrait.php index d03f5613f1a..e8bb9efbbd3 100644 --- a/profile/modules/custom/os_search/tests/src/Traits/SearchTestTrait.php +++ b/profile/modules/custom/os_search/tests/src/Traits/SearchTestTrait.php @@ -107,8 +107,10 @@ protected function generateContent(Group $group, $each_type_count = 5, $differen * To isolate content from others in way (helps asserting correct texts). * @param int $repeat * Repeat max 10 times to check search status. + * @param int $expected_count + * Expected max count as per vsite or global context. */ - protected function getIndexQueryStatus($differentiator = 'searchtest', $repeat = 1) { + protected function getIndexQueryStatus($differentiator = 'searchtest', $repeat = 1, $expected_count = 27) { $this->waitForSeconds(); $query_builder = $this->container->get('os_search.os_search_query_builder'); @@ -117,10 +119,10 @@ protected function getIndexQueryStatus($differentiator = 'searchtest', $repeat = $query_builder->queryBuilder($query); $count = $query->execute()->getResultCount(); - if ($count < 27 && $repeat <= 10) { + if ($count < $expected_count && $repeat <= 10) { $this->getIndexQueryStatus($differentiator, ++$repeat); } - elseif ($count < 27 && $repeat > 10) { + elseif ($count < $expected_count && $repeat > 10) { throw new ExpectationException('No response from elastic server or query is not correct.', $this->getSession()); } } From 229917b1a8a5e83e4dbefe7bf3652ec815599bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 12:58:23 +0100 Subject: [PATCH 29/58] Issue #12689 - Fix detecting group path alias --- profile/modules/vsite/src/Plugin/VsiteContextManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/profile/modules/vsite/src/Plugin/VsiteContextManager.php b/profile/modules/vsite/src/Plugin/VsiteContextManager.php index 303e117047e..3fcfe14020d 100644 --- a/profile/modules/vsite/src/Plugin/VsiteContextManager.php +++ b/profile/modules/vsite/src/Plugin/VsiteContextManager.php @@ -88,9 +88,9 @@ public function getActivePurl() { } /** @var \Drupal\Core\Entity\Query\QueryInterface $query */ - $query = $this->dbConnection->select('url_alias', 'ua') - ->fields('ua', ['alias']) - ->condition('ua.source', "/group/{$group->id()}") + $query = $this->dbConnection->select('path_alias', 'pa') + ->fields('pa', ['alias']) + ->condition('pa.path', "/group/{$group->id()}") ->range(0, 1); /** @var \Drupal\Core\Database\StatementInterface|null $result */ $result = $query->execute(); From 3a5b350970b2408d7f5300cb36abf1411faa6125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sztreha?= Date: Wed, 4 Mar 2020 13:02:43 +0100 Subject: [PATCH 30/58] Issue #12689 - Deprecated https://github.com/sebastianbergmann/phpunit/issues/2198 --- .travis/config/phpunit.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis/config/phpunit.xml b/.travis/config/phpunit.xml index 74981715024..fd424b783f3 100644 --- a/.travis/config/phpunit.xml +++ b/.travis/config/phpunit.xml @@ -9,7 +9,6 @@ beStrictAboutTestsThatDoNotTestAnything="true" beStrictAboutOutputDuringTests="true" beStrictAboutChangesToGlobalState="true" - checkForUnintentionallyCoveredCode="false" convertDeprecationsToExceptions="false">