The "Add new node" button appears even though the user does not have the permission to create nodes of the content type being referenced. Also, a user is able to create a node and the node saves. Expected behavior is that there should be no button if they don't have the ability to create a node of that content type.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sillygwailo created an issue. See original summary.

bojanz’s picture

Confirmed, we're no longer doing any kind of access checking around bundles (D7 checked create access on each bundle).

EDIT: To clarify, this is not intentional, we are simply missing access checking code, and we should add it.

tedbow’s picture

Status: Active » Needs review
FileSize
6.93 KB

Ok here is a patch.

It adds to new InlineEntityFormBase::getCreateBundles to return the bundles the current user can create.

This is used in InlineEntityFormComplex::formElement to determine if add should be shown

It also overrides canBuildForm in each widget class to determine if there are any entity operations that can be done.

Since the simple widget can only add 1 bundle then the user must have access to that.

I think tests will fail because we don't setup the tests with permission for the nested bundles

Status: Needs review » Needs work

The last submitted patch, 3: ief-create_access-2672022-3.patch, failed testing.

tedbow’s picture

Title: "Add new node" button appears despite lacking permissions to add content of that type » IEF field widget do not check for entity create access
Status: Needs work » Needs review
FileSize
5.82 KB
12.75 KB

Ok here is the patch updated with tests and a TEST ONLY patch.

The last submitted patch, 5: ief-create_access-2672022-5-TEST_ONLY.patch, failed testing.

bojanz’s picture

Very close!

+  protected function canBuildForm(FormStateInterface $form_state) {
+    if (parent::canBuildForm($form_state)) {
+      $settings = $this->getSettings();
+      // Return true if the user can create at least 1 bundle
+      // or adding existing entities is allowed.
+      return ($settings['allow_new'] && $this->getCreateBundles())
+        || $settings['allow_existing'];
+    }
+    return FALSE;
+  }
+

This is very unreadable, let's clean it up. The result of the parent:: call should be its own variable, and we should not have two rows of boolean checks paired with a return statement.

tedbow’s picture

Status: Needs review » Needs work

Close but no cigar!

I just figured out I am taking away access to the widget based on create access but widget may actually be editing a node.

Working on this now.

tedbow’s picture

Status: Needs work » Needs review
FileSize
13.36 KB

OK. I don't think my previous approach of checking access in InlineEntityFormBase::canBuildForm

This is because the use might be editing existing entities which they might have access to.

Also the user may not have access add or editing the existing entities but they should still be able reorder reference values if they already exist on the field or also they should be able add existing entities if the widget supports it.

tedbow’s picture

Notes about the previous patch.

  1. +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormBase.php
    @@ -410,4 +432,57 @@ abstract class InlineEntityFormBase extends WidgetBase implements ContainerFacto
    +  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
    +    $element = parent::formMultipleElements($items, $form, $form_state);
    +    if (!$this->canAddNew()) {
    +      if (isset($element['add_more'])) {
    +        // Remove "add more" because the user cannot create any new entities.
    +        unset($element['add_more']);
    +      }
    +      // If the current user cannot add new entities remove "add" forms.
    +      foreach (Element::children($element) as $delta) {
    +        if (isset($element[$delta]['inline_entity_form'])) {
    +          if ($element[$delta]['inline_entity_form']['#op'] == 'add') {
    +            unset($element[$delta]);
    +          }
    +        }
    +      }
    +    }
    +    return $element;
    +  }
    +
    

    This function is overridden to take away the remove both "add more" button and empty "add" forms.

  2. +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormSimple.php
    @@ -51,6 +51,16 @@ class InlineEntityFormSimple extends InlineEntityFormBase {
    +    if ($op == 'edit') {
    +      /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    +      if (!$entity->access('update')) {
    +        $element['entity_label'] = [
    +          '#type' => 'markup',
    +          '#markup' => $entity->label(),
    +        ];
    +        $element['inline_entity_form']['#access'] = FALSE;
    +      }
    +    }
    

    In the simple widget if the user does not have access to edit a specific entity we should still should the label of the entity.

    This allows the user to still reorder the entities when they don't have access to edit all the entities.

tedbow’s picture

Title: IEF field widget do not check for entity create access » IEF field widget do not check for entity create and edit access
Issue tags: +Needs tests

Updating the title because this patch also deals with the fact that simple widget does not check edit access on entities.

Without the patch in #9 a user could edit entities they don't have access to.

I will make a Test for this edit access problem.

tedbow’s picture

Adding a test for access edit on the simple widget.

Basically for all nodes created in InlineEntityFormSimpleWebTest::testSimpleCardinalityOptions

The tests switches the owner of 1 of the child nodes to another user.

Then checks

  1. For the node owned by the other user the title appears but the form does not.
  2. For the nodes owned by the current user the form elements are found

Status: Needs review » Needs work

The last submitted patch, 12: ief-create_access-2672022-12-TEST_ONLY.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review

Only TEST_ONLY patch failed.

bojanz’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests

Almost there.

+  /**
+   * {@inheritdoc}
+   */
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
+    $element = parent::formMultipleElements($items, $form, $form_state);
+    if (!$this->canAddNew()) {
+      if (isset($element['add_more'])) {

This method doesn't belong in the base class, it's specific to the Simple widget, so let's move it there.

Nitpicks:

+      // Check to make target bundles still exist.

Missing word.

+  public function testComplexEntityCreate() {
+
+    $user = $this->createUser([

Unneeded newline before $user.

tedbow’s picture

Status: Needs work » Needs review
FileSize
16.3 KB

Update patch with changes asked for in #15

tedbow’s picture

Update patch with 1 more comment

// Take away access to inline form.
        // getInlineEntityForm still needs to be called for field re-ordering to work.
        $element['inline_entity_form']['#access'] = FALSE;

Because I don't think it is obvious why getInlineEntityForm is still being called.

  • bojanz committed 40c84c9 on 8.x-1.x authored by tedbow
    Issue #2672022 by tedbow, bojanz: IEF field widget do not check for...
bojanz’s picture

Status: Needs review » Fixed

Boom :)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.