Quantcast
Channel: Issues for Drupal core
Viewing all 293902 articles
Browse latest View live

[META] Split up and refactor MediaLibraryTest

$
0
0

Problem/Motivation

MediaLibraryTest is, quite frankly, a mess.

Its coverage is very extensive, but it is also extremely long and complicated, with a lot of repeated code, a few somewhat unreliable parts (though this has significantly improved after #3055648: Frequent random fail in \Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest), and a bloated, unclear scope. It is probably the single most important test in Media Library, but it's not particularly maintainable.

Proposed resolution

First, split MediaLibraryTest into several smaller tests, based on a single base class with common assertions and helpers. For this first step, we won't refactor the tests' business logic; we'll just split them up. They'll be messy, but at least they'll be of a more manageable size: #3095210: Split up MediaLibraryTest

Then, implement various changes that were suggested in other issues related to MediaLibraryTests. Some of these may no longer be applicable due to other changes, but there are many good suggestions in there that are still relevant. These things should be done in sparate issues covering individual classes derived from the big split-up of MediaLibraryTest.

From seanB in #3088681: Make MediaLibraryTest less dependent on representational CSS selectors

  1. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -439,7 +439,6 @@ public function testWidget() {
    -    $this->waitForText('Add or select media');
    

    Maybe it makes sense to still assert the modal title as a generic library UI element? Or add this assert to openMediaLibraryForField?

  2. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -462,8 +461,8 @@ public function testWidget() {
    -    $assert_session->elementNotExists('css', '.media-library-view .media-library-item__edit');
    ...
    +    $assert_session->elementNotExists('css', '.view-media-library .media-library-item__edit');
    +    $assert_session->elementNotExists('css', '.view-media-library .media-library-item__remove');
    

    media-library-item__edit and media-library-item__remove are in the view, so I guess that is fine to keep those.

  3. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -479,22 +478,20 @@ public function testWidget() {
    +    $this->openMediaLibraryForField('field_single_media_type', '#media-library-wrapper');
    

    Can't we fix the openMediaLibraryForField to use a different default $after_open_selector instead of passing the wrapper ID? Or maybe always use the wrapper ID as default? I guess waiting for the media library view makes most sense since that is always going to be there.

  4. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1069,13 +1034,11 @@ public function testWidgetUpload() {
    -    $assert_session->elementExists('css', '.media-library-item__remove')->click();
    +    $assert_session->elementExists('css', '.field--name-field-twin-media')->pressButton('Remove');
    

    We are using .media-library-item__remove earlier in the test since that comes from the view? Why remove it here?

  5. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -2228,21 +2116,35 @@ protected function assertElementExistsAfterWait($selector, $locator, $timeout =
    +  protected function getTypesMenu() {
    

    Do we really need an extra method for this?

  6. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -2351,17 +2253,170 @@ protected function pressSaveButton($expect_errors = FALSE) {
    +  protected function openMediaLibraryForField($field_name, $after_open_selector = '.js-media-library-menu') {
    ...
         return $this->assertElementExistsAfterWait('css', $after_open_selector);
    

    We assert the media library is closed by $this->waitForNoText('Add or select media');. Not sure if we should do the reverse here and assert the title does exist?

  7. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -2351,17 +2253,170 @@ protected function pressSaveButton($expect_errors = FALSE) {
    +    $assert_session->pageTextMatches('/The media items? ha(s|ve) been created but ha(s|ve) not yet been saved. Fill in any required fields and save to add (it|them) to the media library./');
    

    Do we want have a more specific assert for this? We could technically show the wrong message and it would still pass?

  8. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -2351,17 +2253,170 @@ protected function pressSaveButton($expect_errors = FALSE) {
    +  protected function insertSelected($expected_announcement = NULL) {
    ...
    +  protected function getCheckboxes() {
    ...
    +  protected function selectItem($index, $expected_selected_count = NULL) {
    

    These look like method names that are so generic that they might lead to issues in the future if a parent decides to implement them. Maybe make it more media specific?

From @phenaproxima in#3055648: Frequent random fail in \Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest:

  1. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -439,23 +433,19 @@ public function testWidget() {
    +    $this->openMediaLibraryForField('field_unlimited_media');
    +    $this->waitForText('Add or select media');
    

    I think that this waitForText() assertion should be part of openMediaLibraryForField(). I can't think of any circumstance where we wouldn't want to assert the presence of that text as part of opening the media library.

  2. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -439,23 +433,19 @@ public function testWidget() {
    +    $menu = $this->openMediaLibraryForField('field_unlimited_media');
    

    I think it's a little awkward that openMediaLibraryForField() returns the menu by default. I think we should just not have a default value for that parameter (or at least default it to NULL), and make explicit the fact that we want to retrieve the menu once the media library is opened. IOW, this should be $this->openMediaLibraryForField('field_unlimited_media', '.media-library-menu'). Calling $this->openMediaLibraryForField('field_unlimited_media') should not return any element, IMHO.

  3. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -463,23 +453,18 @@ public function testWidget() {
         $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click();
    -    $assert_session->assertWaitOnAjaxRequest();
    

    Nice call on removing this assertWaitOnAjaxRequest() call. There is no reason to wait for AJAX after closing the modal; no AJAX request is triggered by that, as far as I know.

  4. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -489,9 +474,9 @@ public function testWidget() {
    +    $this->waitForElementTextContains('.media-library-selected-count', '0 of 1 item selected');
    

    IMHO, waitForElementTextContains() should follow similar patterns to what we get from Mink. In other words, it shouldn't force you to use a CSS selector; it should be something like $this->waitForElementTextContains('css', '.media-library-selected-count', '0 of 1 item selected').

  5. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -514,18 +498,15 @@ public function testWidget() {
    -    $assert_session->buttonExists('Show row weights')->press();
    +    $this->assertElementExistsAfterWait('css', '#field-twin-media .tabledrag-toggle-weight')->press();
    

    This seems interesting; why the change from a button value to a CSS selector?

  6. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -690,8 +651,7 @@ public function testWidget() {
    +    $this->switchToMediaType('One');
    

    I don't know how I feel about the "magic" of $this->switchToMediaType('One'), when the actual name of the media type is "Type One". I'd rather this (and all similar calls) was more explicit, i.e. $this->switchToMediaType('Type One').

  7. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -699,9 +659,8 @@ public function testWidget() {
    +    $open_button = $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"]');
         $this->assertTrue($open_button->hasAttribute('data-disabled-focus'));
         $this->assertTrue($open_button->hasAttribute('disabled'));
    

    These can be collapsed into one line:

    $this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"][data-disabled-focus][disabled]').

  8. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -972,18 +919,16 @@ public function testWidgetAnonymous() {
         $this->assertNotEmpty($assert_session->waitForText('Added one media item.'));
    -    $assert_session->assertWaitOnAjaxRequest();
    

    Why didn't this change to $this->waitForText()?

  9. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -997,6 +942,9 @@ public function testWidgetAnonymous() {
    +   * Note that this test will occasionally fail with SQLite until
    +   * https://www.drupal.org/node/3066447 is addressed.
    

    This should be a @todo.

  10. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1166,13 +1099,13 @@ public function testWidgetUpload() {
    -    $page->attachFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_3));
    -    $assert_session->assertWaitOnAjaxRequest();
    +    $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_uri_3));
    +    $this->waitForText('The media item has been created but has not yet been saved.');
         $assert_session->checkboxChecked("Select $existing_media_name");
    

    This looks like a change in logic. Wouldn't we want to wait for the "Select $existing_media_name" field instead, to keep it in line with what it previously was?

  11. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1200,81 +1133,74 @@ public function testWidgetUpload() {
    +    $this->waitForText("Select $existing_media_name");
    

    Isn't this the name of a field? If so, wouldn't we want to wait for the field to exist, rather than some text? This feels a bit "coincidental" otherwise.

  12. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1472,33 +1389,33 @@ public function testWidgetOEmbed() {
    +    // assertWaitOnAjaxRequest() required for input "id" attributes to
    +    // consistently match their label's "for" attribute.
         $assert_session->assertWaitOnAjaxRequest();
    

    So, question about this. If we are waiting for a specific condition (the input 'id' to match the label 'for'), couldn't we use $this->assertJsCondition() or similar for that? Do we need to use assertWaitOnAjaxRequest()?

From @phenaproxima in#3055648: Frequent random fail in \Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest

  1. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    -    $assert_session->assertWaitOnAjaxRequest();
    +    $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_one]"][checked="checked"]');
         $page->checkField('settings[handler_settings][target_bundles][type_two]');
    -    $assert_session->assertWaitOnAjaxRequest();
    +    $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_two]"][checked="checked"]');
         $page->checkField('settings[handler_settings][target_bundles][type_three]');
    -    $assert_session->assertWaitOnAjaxRequest();
    +    $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_three]"][checked="checked"]');
    

    Nit: I think we can change [checked="checked"] to just [checked]. That is a boolean attribute, so its value doesn't really matter. :)

  2. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +  protected function assertElementExistsAfterWait($selector, $locator, $timeout = 10000) {
    

    I think we should rename this to waitForElement(), which IMHO would be clearer and less verbose.

  3. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +    $lowercase_type = strtolower($type);
    

    This should be mb_strtolower().

  4. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +    $this->assertElementExistsAfterWait('css', "[data-drupal-media-type='type_$lowercase_type']");
    

    I'm not entirely clear on why we need this -- what is it adding? Can we get a comment? above it?

  5. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +    // assertWaitOnAjaxRequest() required for input "id" attributes to
    +    // consistently match their label's "for" attribute.
    +    $this->assertSession()->assertWaitOnAjaxRequest();
    

    Ah, now I see why we can't wait for a particular condition instead of doing this: because we're waiting for all input IDs to match the 'for' attributes. Yeah, that'd be pretty impossible to "wait" for. I guess assertWaitOnAjaxRequest() is our only option. For now.

  6. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +   * @param string $selector_type
    +   *   Element selector type (css, xpath)
    +   * @param string|array $selector
    +   *   Element selector.
    

    These should be renamed $selector and $locator for consistency with Mink.

  7. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +    $page = $this->getSession()->getPage();
    +
    +    $start = microtime(TRUE);
    +    $end = $start + ($timeout / 1000);
    +    do {
    +      $nodes = $page->findAll($selector_type, $selector);
    +      if (count($nodes) === $count) {
    +        return;
    +      }
    +      usleep(100000);
    +    } while (microtime(TRUE) < $end);
    +
    +    $this->assertSession()->elementsCount($selector_type, $selector, $count);
    

    I'm still not clear on why we don't use $page->waitFor() here? Something like:

    $result = $this->getSession()->getPage()->waitFor($timeout / 1000, function ($page) use ($selector, $locator, $count) {
      return count($page->findAll($selector, $locator)) === $count;
    });
    $this->assertSame($result, $count);
    
  8. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +  protected function waitForFieldExists($field, $timeout = 10000) {
    

    Can we rename this waitForField(), for consistency?

  9. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +  /**
    +   * Waits for a file field to exist before uploading.
    +   */
    +  public function addMediaFileToField($locator, $path) {
    +    $page = $this->getSession()->getPage();
    +    $this->waitForFieldExists($locator);
    +    $page->attachFileToField($locator, $path);
    +  }
    

    This can be refactored: $this->waitForFieldExists($locator)->attachFile(). No need to use $page. Honestly, since it's so simple, we might be able to just remove this method entirely.

  10. +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
    @@ -1653,13 +1564,201 @@ public function testFieldUiIntegration() {
    +  protected function saveAnd($operation) {
    +    $this->assertElementExistsAfterWait('css', '.ui-dialog-buttonpane')->pressButton("Save and $operation");
    

    I'm a bit iffy on the magic string concatenation we're doing, but...it's probably fine for now. This is not, after all, an API.

Remaining tasks

All of it.

User interface changes

None whatsoever.

API changes

MediaLibraryTest is not an API. So, although it will change extensively, there are no API changes.

Data model changes

Certainly not.

Release notes snippet

None expected.


Exclude development libraries from templates' composer.json by default

$
0
0

On the production server, and as a site builder, you shouldn't need the development libraries. So I suggest that development libraries are not included by default in Drupal core. Also, in that way the --no-dev and --update-no-dev parameters are no longer necessary for everyday-site-building.

How to create and manage a project without development libraries in the new version 8.8, where -n equals --no-interaction:

$ composer create-project drupal/recommended-project:^8.8@dev -n --no-dev mysite
$ composer update --with-dependencies --no-dev
$ composer require --update-no-dev drupal/admin_toolbar

On one hand, adding the developer tools project with for example a command like composer require drupal/devtools will be an extra step for Drupal developers, who are deep in the code. On the other hand, the benefits for those who mostly don't need these tools, like new Drupal users, site builders and dev ops people, there will be benefits. For example for dev ops people, the reduced complexity will mean less risk of unforeseen Composer events during a security update situation, like a lingering git commit blocking everything, which can grind the process down to a halt.

If the composer update --with-dependencies process breaks down, while applying late night security updates, having to debug why it happens, while under the the pressure of rolling out updates is not optimal, and might make dev ops people a little less fond of Drupal in the long run. Running composer update should be as boring a non-event as possible, and the chances of a smooth process should be maximized, by getting potential obstacles out of the way.

While there "shouldn't" be a problem, stuff happens, like with .git repository should not be included with composer package, where rfay comments:

This seems to break every composer update I do, have to remove the coder directory in vendor to fix.

Changing to a default installation, without dev dependencies

Pros

  • For new Drupal users there will be less moving parts and reduced complexity
  • No need to remember to use --no-dev and --update-no-dev
  • You don't get a screen load of updates, and changed composer.json if you forget to add --update-no-dev
  • Composer can calculate dependencies faster during composer update
  • Less risk of unforeseen Composer events, like a lingering git commit blocking composer update
  • Less changes in composer.lock, giving less results running git diff and better overview

Cons

  • The work involved in containing the developer tools in its own drupal/devtools project
  • Developers have to run composer require drupal/devtools

Statistics

Result with --no-dev, 53 packages

$ composer create-project drupal/recommended-project:^8.8@dev -n --no-dev mysite
Installing drupal/recommended-project (8.8.x-dev 995d694d3cf9c0863bb170e7c62c8f1aa6d35437)
  - Installing drupal/recommended-project (8.8.x-dev 995d694): Cloning 995d694d3c from cache
Created project in mysite
Loading composer repositories with package information
Updating dependencies
Package operations: 53 installs, 0 updates, 0 removals
  - Installing composer/installers (v1.6.0): Loading from cache
...

Stats: 24.534 items (and 91 hidden), totalling 391,2 MB

Result without --no-dev, 106 packages

$ composer create-project drupal/recommended-project:^8.8@dev -n mysiteDEV
Installing drupal/recommended-project (8.8.x-dev 995d694d3cf9c0863bb170e7c62c8f1aa6d35437)
  - Installing drupal/recommended-project (8.8.x-dev 995d694): Cloning 995d694d3c from cache
Created project in mysiteDEV
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 106 installs, 0 updates, 0 removals
  - Installing composer/installers (v1.6.0): Loading from cache
...

Stats: 29.914 items (and 208 hidden), totalling 414,8 MB

Provide an example of how to manage robots.txt and .htaccess with Composer

$
0
0

Problem/Motivation

Users are encouraged to modify their .htaccess file directly in a comment in that same file; since this comment has been in place for a while, people are used to doing it. Unfortunately, this sort of modification is erased during Drupal updates (e.g. when running drupal pm-update), and with the introduction of the Drupal Composer Scaffold tool, composer install also puts these files in danger of being overwritten. See #3092563: Avoid overwriting .htaccess changes during scaffolding for some of the implications of this.

It would be desirable if we could start guiding users towards a more modern, Composer-based way to manage their .htaccess and robots.txt customizations. The Drupal Composer Scaffold tool provides patching and append/prepend features to make these changes easier to maintain, for example.

Proposed resolution

Add two examples to drupal/recommended-project:

  1. Prepend to robots.txt
  2. Patch .htaccess

These examples should not be added to the legacy project for now, as that is used to generate downloaded tarballs.

Remaining tasks

tbd

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

tbd

Reconsider how defaultTheme is defined in file.module Functional tests

$
0
0

Problem/Motivation

Most of the test classes under core/modules/file/tests/src/Functional are derived from either FileFieldTestBase or FileManagedTestBase. Both of those define their own static $modules array.

However, when we did #3082655: Specify the $defaultTheme property in all functional tests we didn't notice this fact, and put separate $defaultTheme definitions in all the children.

3 of them apparently depended on classy markup, so those set defaultTheme to classy. Everything else uses stark.

In addition to being duplicate code in most cases, these hunks can cause otherwise backportable test changes / additions to require separate patches for different branches, which is a minor hassle and creates more work for ourselves.

Proposed resolution

  • Put protected $defaultTheme = 'stark'; in the parent test classes.
  • Remove that from (almost) all the child classes.
  • Let the 3 tests that (apparently) need 'classy' to continue to override $defaultTheme themselves.

Remaining tasks

  1. Do it.
  2. Make sure we didn't break anything.
  3. Review.
  4. RTBC.
  5. Commit.

User interface changes

-

API changes

None. Tests aren't API.

Data model changes

-

Release notes snippet

-

New Custom Blocks are not added to Views Reference drop-down

$
0
0

So I have enabled the archive view and created my own custom block that will display certain news articles. I wanted to use layout manager to create a 2-column page with a 75-25 sizing ratio. the news articles would take up 75% and the archive would act as a sort of sidebar (my website's theme does not have a sidebar unfortunately). Unfortunately when I go to embed block and click the drop-down for "Block to Embed" or "Views reference" neither of those blocks show up. I'm very confused as to why this is and what I could do to correct this, as the documentation says it should support custom blocks, so I'm probably missing something.

Steps:
1. Create custom block and/or enable archive view/block
2. Create new layout manager content, name it whatever you want
3. Click the button at the bottom that says "layout" to edit the layout
4. Click "Add Section" and pick any size, I just listed the sizes I was interested in specifically.
5. Click "Add Block" and then click "Create Custom Block"
6. Click "Embed Block"
7. Click the drop-down for "Block to Embed" or "Views reference" and your view might not be there, it hasn't in my case

If I can clarify anything please ask for clarification and I'll try to get back as soon as possible!

Hardening: disable user picture field for anonymous users by default

$
0
0

Problem/Motivation

Files are Hard(tm). ;) Safely handling files is hard.

Out of the box, core allows anonymous users access to upload files to your site via the user picture profile field. We probably shouldn't do that. Even if the site requires admin approval before a user can login, the file has already been uploaded to the server, and a potential file-related exploit is exploitable.

True, many sites don't require admin approval, and an attacker can login and upload the file that way, but it's a bit harder to script/automate that.

IMHO, core shouldn't allow anonymous users to upload files unless a site builder goes out of their way to enable that.

Note: I initially submitted this to security.drupal.org but was told it could be handled as a public hardening issue.

Proposed resolution

Remove the default user_picture field from the 'Register' form mode for user entities. We'll probably need to do this separately for each of the core install profiles.

AFAICT, there's no API-first way to register users, but if I'm wrong about that, we should not just do this at the form UI level, but also in whatever underlying field-level access hook thingy we can use that will be enforced by API and UI alike.

Remaining tasks

  1. Write code (mostly config changes).
  2. Add/update tests to make sure anonymous can't upload files by default.
  3. Review.
  4. RTBC.
  5. Commit.

User interface changes

Anonymous users creating accounts can't upload any files. They only see the user_picture field after they successfully login.

API changes

TBD, probably none.

Data model changes

TBD, probably none.

Release notes snippet

TBD.

Add support for additional protocols in Link field definition

$
0
0

Problem/Motivation

The link module only validates http and https, but not other scheme names such as git or ftp.

In Drupal 7, the validation can be turned off, thereby allowing the input of other scheme names. D7 sites could use this to use other scheme names, which will then not be valid in D8 any more.

Even better would be a option in the field configuration to set which scheme names are valid for this field.

Proposed resolution

Add more protocols to the list of allowed protocols.
Allow custom protocols.

Remaining tasks

List protocols which will be validated by Drupal.

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Browser conditional comments broken

$
0
0

Problem/Motivation

Coming from fixing the CSS Variables po[ln]yfill for IE, i stumbled upon this:

How to reproduce:

* Want to add library CSS/JS browser-conditional like so:

my_library:
  js:
    run-cssvars-polyfill.js:
      browsers: { '!IE': false }

Result:
* CSS/JS is wrapped in a browser-switch comment like this:

<!--[if IE]>
<script src="/modules/contrib/cssvars/polyfill/libraries/css-vars-polyfill.min.js?q16qed"></script>
<![endif]-->

Alas, M$ dropped the conditional script comment tag in 2016 since IE10 (SO). So it seems that the resulting browser switch comments only work up to IE9 (see #2390621: [policy, no patch] Update Drupal's browser support policy on why this is EOL but still supported).

Proposed resolution

* Update docs.

Once we drop IE9,

* Remove the functionality.
* Error out or add warning if developers use it.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet


Drupal\contact\Entity\Message does not contain entity_key "id"

$
0
0

Hey there!

I'm having a weird problem with Drupal\contact\Entity\Message-entities in Drupal 8.7.6.

We are using multiple Contact forms with some extra fields added via field-module.

Everything is working fine, but when I navigate to status report (/admin/reports/status), the site crashes with the following error:

Error: Call to a member function getType() on null in Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->getDedicatedTableSchema() (line 2213 of /var/www/html/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php)

Here's the code that causes the crash:

protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $storage_definition, ContentEntityTypeInterface $entity_type = NULL) {
	$entity_type = $entity_type ?: $this->entityType;
	$description_current = "Data storage for {$storage_definition->getTargetEntityTypeId()} field {$storage_definition->getName()}.";
	$description_revision = "Revision archive storage for {$storage_definition->getTargetEntityTypeId()} field {$storage_definition->getName()}.";

	$id_definition = $this->fieldStorageDefinitions[$entity_type->getKey('id')];
	if ($id_definition->getType() == 'integer') {
	  // ...
	}
	// ...
}

It seems that the $entity_type (ContentEntityType with a class of Drupal\contact\Entity\Message) does not have the entity_key 'id'. Upon closer inspection that seems to be the case: $entity_type->hasKey('id') // => FALSE.

Message-entity annotation does not define an entity_key for id:

/**
 * Defines the contact message entity.
 *
 * @ContentEntityType(
 *   id = "contact_message",
 *   label = @Translation("Contact message"),
 *   label_collection = @Translation("Contact messages"),
 *   label_singular = @Translation("contact message"),
 *   label_plural = @Translation("contact messages"),
 *   label_count = @PluralTranslation(
 *     singular = "@count contact message",
 *     plural = "@count contact messages",
 *   ),
 *   bundle_label = @Translation("Contact form"),
 *   handlers = {
 *     "access" = "Drupal\contact\ContactMessageAccessControlHandler",
 *     "storage" = "Drupal\Core\Entity\ContentEntityNullStorage",
 *     "view_builder" = "Drupal\contact\MessageViewBuilder",
 *     "form" = {
 *       "default" = "Drupal\contact\MessageForm"
 *     }
 *   },
 *   admin_permission = "administer contact forms",
 *   entity_keys = {
 *     "bundle" = "contact_form",
 *     "uuid" = "uuid",
 *     "langcode" = "langcode"
 *   },
 *   bundle_entity_type = "contact_form",
 *   field_ui_base_route = "entity.contact_form.edit_form",
 * )
 */

It seems that Message is also the only entity in core without an "id" entity_key (aside from Drupal\entity_test\Entity\EntityTestNoId). Also it seems that the key has never been there.

If I modify the method getDedicatedTableSchema by adding a default value, the status report page renders fine:

protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $storage_definition, ContentEntityTypeInterface $entity_type = NULL) {
    $entity_type = $entity_type ?: $this->entityType;
    $description_current = "Data storage for {$storage_definition->getTargetEntityTypeId()} field {$storage_definition->getName()}.";
    $description_revision = "Revision archive storage for {$storage_definition->getTargetEntityTypeId()} field {$storage_definition->getName()}.";

    $id_key = $entity_type->getKey('id');
    if ($id_key === FALSE) {
      $id_key = 'id';
    }
    $id_definition = $this->fieldStorageDefinitions[$id_key];

    if ($id_definition->getType() == 'integer') {
      // ...
    }
    // ...
}

This error has persisted on our production site through multiple Drupal versions but the messaging feature has been working flawlessly.

Could anyone point me to the right direction to fix this annoying error?

Improve external URL validation in many ways

$
0
0

Problem/Motivation

While working in some issues I realized the need to improve UrlHelper::isValid()( in the file ./core/lib/Drupal/Component/Utility/UrlHelper.php

The issues I've found:

  • Punycode (International Domain Names) URLs cannot be validated
  • It does not accept protocol-relative URLs
  • It does not take in account the allowed protocols because it does not use UrlHelper::getAllowedProtocols()
  • It uses custom regex, while we could use Symfony UrlValidator which has a similar regex

Currently the Symfony UrlValidator also has some issues:

  • It depends of context, which is not available at UrlHelper::isValid()
  • Its code has some bugs displaying the exception's messages

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

FileFieldWidgetTest fails on local sites running in a subdirectory

$
0
0

Problem/Motivation

I have a local 8.8.x dev site.
It lives at http://localhost/drupal-8_8
When I try to run core/modules/file/tests/src/Functional/FileFieldWidgetTest.php locally, it fails with 5 of these:

1) Drupal\Tests\file\Functional\FileFieldWidgetTest::testSingleValuedWidget
Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.

When I use run-tests and inspect the HTML output, I see this:

GET request to: http://localhost/drupal-8_8/drupal-8_8/sites/simpletest/93134289/files/2019-11/text-0.txt

Notice the double "drupal-8_8" in there?

Digging a bit deeper, each of the calls that fails is something like this:

  $this->drupalGet($node_file->createFileUrl());

Looking at core/modules/file/src/Entity/File.php we find this:

  public function createFileUrl($relative = TRUE) {

So somehow, using relative file links in the test is confusing phpunit + run-tests.sh for me.

Proposed resolution

Invoke createFileUrl() with FALSE to always get absolute links, instead of relying on relative links.

Remaining tasks

  1. Do it.
  2. Make sure it doesn't break anything (passes locally).
  3. Review.
  4. RTBC.
  5. Commit.

User interface changes

-

API changes

-

Data model changes

-

Release notes snippet

-

Add a SECURITY.md explaining how to report security vulnerabilities properly

$
0
0

GitHub has recently started to make use of SECURITY.md files if present in the repository root. Many open source projects have since stared to have a SECURITY.md file explaining how to report security vulnerabilities properly.

Just a moments ago, we got WordPress to commit their SECURITY.md file, and I would like to propose that we use a SECURITY.md file as well.

This file can explain the procedures we have security.drupal.org, how to report a Drupal core vulnerability, how it works for core, security coverage, and a lot of other information that will surely make it easier for security researchers and end users alike.

Thank you.

Menu system should redirect to the particular menu's link listing after adding a link

$
0
0

Hi all,

I just found one issue in menu configuration. When you add link to a menu, it was redirection to the menu type listing page. Actually, it should redirect to that particular menu links listing page.

Thanks & Regards,
Saranya.P

Drupal 8.8 on Postgresql 12

$
0
0

Hi,

Tried to run drupal 8.7 on Postgresql 12beta1.
It does not run, is version 12 supported ?

Regards,

Replace 'gsw-berne' (Swiss German language) with 'gsw' (W3C compliant)

$
0
0

Problem / Motivation

The wrong (by W3C) head hreflang="gsw-berne" HTML tag:

<link rel="alternate" hreflang="gsw-berne" href="https://www.domainXXX.com/ch/ihr-spezialist-fur-abdichtungen-und-markierungen" />

which is reported by W3C (https://validator.w3.org/) as the following error (I attach a screenshot as well):

Error: Bad value gsw-berne for attribute hreflang on element link: Bad variant subtag berne.

From line 22, column 1; to line 22, column 128

<link rel="alternate" hreflang="gsw-berne" href="https://www.domainXXX.com/ch/ihr-spezialist-fur-abdichtungen-und-markierungen" />↩<link

Resolution

To replace core language 'gsw-berne' (German Swiss language) with 'gsw' (W3C compliant).


How to change "FIELD TYPE"?

$
0
0

I have a website for around 2 years. The website has a lot of data.

Problem:-
I have wanted to change "FIELD TYPE"?

I have taken "Term reference" and I want "Entity Reference"

Please help me this is possible or not?

If this is possible without losing any data. Please let me know.

Drupal 7 date fields with "todate" ("End date" in UI) setting enabled to collect a range lose their end date upon migration: data loss!

$
0
0

Problem/Motivation

The Drupal 7 date module allowed the site builder to configure whether to collect an end date or not:

(This is called 'todate' in the code.)

For example, on my personal site, I have a projectNodeType which has a "time range"date. Example: https://wimleers.com/work/project/ledgrid.

Upon migration, the start value (value) is migrated, but the end value (value2) is dropped

D7

D8 HEAD

That's because this is being migrated to a @FieldType=datetime field in D8 instead of a @FieldType=daterange field in D8!

⚠️🔥 This is data loss! 🔥 ⚠️

Proposed resolution

Make \Drupal\datetime\Plugin\migrate\field\DateField detect the todate setting and:

  1. expand the process chain to also transform data for @FieldType=daterangeend_value property, instead of only the value property
  2. dynamically override the statically computed destination field type: return daterange instead of datetime when appropriate
  3. most simple, but perhaps most controversial: change the destination_module key in the @MigrateField annotation to datetime_range instead of datetime. The migration system seems to not have been designed for dynamic conditional edge cases like this one, and the harm of requiring that module to be installed even if unused is minimal; and certainly does not outweigh the data loss that is currently happening.

Remaining tasks

TBD

User interface changes

N/A

API changes

N/A

Data model changes

N/A

Release notes snippet

TBD

comment_entity_storage_load() is too expensive on cold caches

$
0
0

Problem/Motivation

comment_entity_storage_load() attempts to optimize away a database query each time entities are loaded that don't have comment fields attached.

Unfortunately when caches are cold - such as after submitting the modules page, the field check takes 125ms and 4mb of memory.

Proposed resolution

Query statistics just-in-time and in bulk to avoid needing the loading etc and the field checks.

Remaining tasks

Uploading a patch for #1, but I think we should do #2 (which will be slightly more work).

User interface changes

API changes

New service
New data-types

#size for Select field documentation is wrong

UnmetDependenciesException when installing Drupal 8

$
0
0

Read this First

If you have been affected by this, read over the system requirements to be certain the platform on which you are installing meets them.

Original Report

Some unknown system requirement or setting not specified in the requirements is rendering Drupal uninstallable.

Manifests as: Cannot install Drupal, hangs at "Installing Drupal: Initializing"
Initializing
I let it hang all night, tried 5 or 6 times. It managed to created some database entries (screenshot). The only install warning I got was no opcache (due to a recent update config problem), otherwise, I generally run bloated PHP scripts and massive D6/D7 sites on my local all the time and have no problems.

I have marked this as "critical" because, well, it blocks installation. Using minimal install, mariadb.

Here's the output of the error page when I eventually interrupt the process:

Error
The website encountered an unexpected error. Please try again later.
Drupal\Core\Config\UnmetDependenciesException: Configuration objects (block.block.stark_admin, block.block.stark_branding, block.block.stark_local_actions, block.block.stark_local_tasks, block.block.stark_login, block.block.stark_messages, block.block.stark_page_title, block.block.stark_tools) provided by minimal have unmet dependencies in Drupal\Core\Config\UnmetDependenciesException::create() (line 89 of core/lib/Drupal/Core/Config/UnmetDependenciesException.php).

Drupal\Core\Config\UnmetDependenciesException::create('minimal', Array)
Drupal\Core\Config\ConfigInstaller->checkConfigurationToInstall('module', 'minimal')
Drupal\Core\ProxyClass\Config\ConfigInstaller->checkConfigurationToInstall('module', 'minimal')
Drupal\Core\Extension\ModuleInstaller->install(Array, )
Drupal\Core\ProxyClass\Extension\ModuleInstaller->install(Array, )
install_install_profile(Array)
install_run_task(Array, Array)
install_run_tasks(Array)
install_drupal(Object)

Here is my phpinfo(). I'm happy to give any other output, I use a debugger and can give useful debug information.

Viewing all 293902 articles
Browse latest View live