Trying to write a custom module tying in ACL with commerce_license (to purchase access to content), but I'm not sure I'm implementing the ACL API correctly. Everything seams to be in the database, however. I'm probably missing a step, but I'm not sure what that is.

User is uid 3. Node I'm trying to access is node/23. ACL is 16.

ACL is listed in acl table. Node is listed in acl_node table, with grant view only. User is listed in acl_user table.


mysql> select * from acl WHERE acl_id = 16;
+--------+----------------------+-----------+--------+
| acl_id | module               | name      | number |
+--------+----------------------+-----------+--------+
|     16 | commerce_license_acl | ACL_4_23  |   NULL |
+--------+----------------------+-----------+--------+


mysql> select * from acl_node WHERE acl_id = 16;
+--------+-----+------------+--------------+--------------+----------+
| acl_id | nid | grant_view | grant_update | grant_delete | priority |
+--------+-----+------------+--------------+--------------+----------+
|     16 |  23 |          1 |            0 |            0 |        0 |
+--------+-----+------------+--------------+--------------+----------+


mysql> select * from acl_user WHERE acl_id = 16;
+--------+-----+
| acl_id | uid |
+--------+-----+
|     16 |   3 |
+--------+-----+

Attached is DNA screenshot showing user is not authorized (logged in user is uid 3).

CommentFileSizeAuthor
DNA.png70.86 KBjoshua.albert

Comments

salvis’s picture

Status: Active » Fixed

You're missing the entry in the {node_access} table.

Try calling node_access_acquire_grants() on node 23 after setting up ACL.

joshua.albert’s picture

Sorry, I'm not sure what you mean.

You mean I should place this in the save() function of my license plugin (this is where I'm creating the acl and adding the node and user to it)? Doesn't rebuilding the access permissions call node_access_acquire_grants()? I've rebuilt access permissions and I'm still not getting anything.

Here is the code for my plugin:


if ($this->uid && $this->product_id) {

      // Get the entity referenced 
      $node = $this->wrapper->product->commerce_license_acl_node->value();

      $acl_name = 'view_' . $node->nid;

      // Get the acl associated with this node and product ID
      $acl_id = acl_get_id_by_name('commerce_license_acl', $acl_name);

      // If the ACL doesn't already exist, create it
      if(empty($acl_id)){

        // Create ACL if one is not already associated with this license
        $acl_id = acl_create_acl('commerce_license_acl', $acl_name);

        // Grant read access. TODO: Grant access to this node based on product configuration
        $read   = TRUE; // $this->wrapper->product->commerce_licence_acl_read->value();
        $update = FALSE; // $this->wrapper->product->commerce_licence_acl_update->value();
        $delete = FALSE; // $this->wrapper->product->commerce_licence_acl_delete->value();

        acl_node_add_acl($node->nid, $acl_id, $read, $update, $delete, 0);

      }

      $owner = $this->wrapper->owner->value();

      switch($this->status){
        case COMMERCE_LICENSE_ACTIVE:
          acl_add_user($acl_id, $owner->uid);
          break;
        case COMMERCE_LICENSE_EXPIRED:
          acl_remove_user($acl_id, $owner->uid);
          break;
        default:
          // do nothing
          break;
      }
      
      // Is this where I should be putting the call to node_access_acquire_grants()?
      node_access_acquire_grants($node);

}

I run this, test it out, and the same thing - there are records in the acl tables, but nothing in the node_access table.

salvis’s picture

Doesn't rebuilding the access permissions call node_access_acquire_grants()?

Yes, but you have to call node_access_acquire_grants() (yes, as in #2) because you don't want to rebuild all the access permissions every time.

I've rebuilt access permissions and I'm still not getting anything.

Did you implement hook_enabled()?

function MYMODULE_enabled($set = NULL) {
  static $enabled = TRUE; // not drupal_static!
  if ($set !== NULL) {
    $enabled = $set;
  }
  return $enabled;
}

ACL will not return its NA records for your module if your module does not confirm that it's active.

Also, your module should implement hook_disable():

function MYMODULE_disable() {
  MYMODULE_enabled(FALSE);
}

Status: Fixed » Closed (fixed)

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

joshua.albert’s picture

Yes, I've implemented both hook_enabled() and hook_disable().

I'm still not getting anything listed in the node_access records.

joshua.albert’s picture

Status: Closed (fixed) » Active
joshua.albert’s picture

I've noticed in the acl_node_grants() function, we are returning an array of acl ids. I don't see anything in the node_access records with a realm of "acl".

When are the acl tables converted to node_access records, if not in the acl_node_grants() function?

salvis’s picture

Issue summary: View changes

I've noticed in the acl_node_grants() function, we are returning an array of acl ids. I don't see anything in the node_access records with a realm of "acl".

That's the query side of node access.

When are the acl tables converted to node_access records, if not in the acl_node_grants() function?

In https://api.drupal.org/api/drupal/modules!node!node.module/function/node...
After your module has set up the ACL records, it must call that function. This will call acl_node_access_records() which will return the data that goes into the node_access table.

But I thought you were already calling node_access_acquire_grants()...

Your DNA screenshot...

... does show 'acl' records, but it says "no users" for node/23. So it seems like acl_add_user() is not getting called as you expect. This may well cause acl_node_access_records() to not return them, because they'd be irrelevant — I'm not sure.

If you hover your mouse over "empty" it'll tell you what exactly it means.

joshua.albert’s picture

Sorry. That was a month ago. There have been some modifications to the code recently, but I didn't think they would affect anything. However, something must have broke somewhere along the way, because now the acl realm isn't showing anywhere in the node_access table or DNA, even though the acl, acl_node, and acl_user tables are populated correctly.

  function save(){

    if ($this->uid && $this->product_id) {



      // Get the entity referenced 
      $node = $this->wrapper->product->commerce_license_acl_node->value();

      $acl_name = 'view_' . $node->nid;

      // Get the acl associated with this node and product ID
      $acl_id = acl_get_id_by_name('commerce_license_acl', $acl_name);

      // If the ACL doesn't already exist, create it
      if(empty($acl_id)){

        // Create ACL if one is not already associated with this license
        $acl_id = acl_create_acl('commerce_license_acl', $acl_name);
      }

      $read   = TRUE; 
      $update = FALSE; 
      $delete = FALSE; 

      $related_nodes = $this->get_all_referenced_nodes($node);

      foreach($related_nodes as $related_nid){
        acl_node_add_acl($related_nid, $acl_id, $read, $update, $delete, 0);
      }

      acl_node_add_acl($node->nid, $acl_id, $read, $update, $delete, 0);

      $owner = $this->wrapper->owner->value();

      switch($this->status){
        case COMMERCE_LICENSE_ACTIVE:
          acl_add_user($acl_id, $owner->uid);
          break;
        default:
          acl_remove_user($acl_id, $owner->uid);
          break;
      }

      foreach($related_nodes as $related_nid){
        $related_node = node_load($related_nid);
        node_access_acquire_grants($related_node);
      }

      node_access_acquire_grants($node);

    }

    parent::save();

  }

My other module (which implements hook_node_access, hook_node_access_records and hook_node_grants) seams to be working fine, as well, here:

joshua.albert’s picture

"it says "no users" for node/23. So it seems like acl_add_user() is not getting called as you expect."

Here are my acl tables:


mysql> select * from node_access where nid IN (24, 27, 20, 25, 22, 23);
+-----+-----+-----------------+------------+--------------+--------------+
| nid | gid | realm           | grant_view | grant_update | grant_delete |
+-----+-----+-----------------+------------+--------------+--------------+
|  20 |   0 | all             |          1 |            0 |            0 |
|  22 |   0 | all             |          1 |            0 |            0 |
|  23 |   0 | all             |          1 |            0 |            0 |
|  24 |  24 | custom_realm1   |          1 |            0 |            0 |
|  25 |   0 | all             |          1 |            0 |            0 |
|  27 |  27 | custom_realm2   |          1 |            0 |            0 |
+-----+-----+-----------------+------------+--------------+--------------+
7 rows in set (0.00 sec)

mysql> select * from acl;
+--------+----------------------+---------+--------+
| acl_id | module               | name    | number |
+--------+----------------------+---------+--------+
|     45 | commerce_license_acl | view_23 |   NULL |
+--------+----------------------+---------+--------+
1 row in set (0.00 sec)

mysql> select * from acl_node;
+--------+-----+------------+--------------+--------------+----------+
| acl_id | nid | grant_view | grant_update | grant_delete | priority |
+--------+-----+------------+--------------+--------------+----------+
|     45 |  20 |          1 |            0 |            0 |        0 |
|     45 |  22 |          1 |            0 |            0 |        0 |
|     45 |  23 |          1 |            0 |            0 |        0 |
|     45 |  24 |          1 |            0 |            0 |        0 |
|     45 |  25 |          1 |            0 |            0 |        0 |
|     45 |  27 |          1 |            0 |            0 |        0 |
+--------+-----+------------+--------------+--------------+----------+
6 rows in set (0.00 sec)

mysql> select * from acl_user;
+--------+-----+
| acl_id | uid |
+--------+-----+
|     45 |  99 |
+--------+-----+
1 row in set (0.00 sec)


If the acl_add_user() is not being called, how is the user being added to the acl_user table?

salvis’s picture

Well, that's the conclusion I drew from what the original DNA showed. What is it showing now?

After you've made the screenshot, have you tried to rebuild permissions? Does that make any difference?

Your ACL tables look ok.

joshua.albert’s picture

The DNA listing is showing that everybody, including anon users, has access to node 23.

node	prio	 status	realm	gid	view	update	delete	explained
23	–	default	all	0	1′	0	0	All users may view this node.

Hovering over "default" shows the message "Default grant supplied by core in the absence of any other non-empty grants; in {node_access}."

As shown above, this is what I have in the node_access table:


mysql> select * from node_access where nid = 23;
+-----+-----+-----------------+------------+--------------+--------------+
| nid | gid | realm           | grant_view | grant_update | grant_delete |
+-----+-----+-----------------+------------+--------------+--------------+
|  23 |   0 | all             |          1 |            0 |            0 |
+-----+-----+-----------------+------------+--------------+--------------+
1 rows in set (0.00 sec)

To answer your question, yes, I've cleared cached and rebuilt permissions.

joshua.albert’s picture

Status: Active » Closed (works as designed)

Figured it out. It was the enabled() hook. I had misspelled the function name, so acl_node_access_records() was bypassing and not returning the grants. Oops. Thanks for your help.

salvis’s picture

Ok, thanks for following up.