When I save a feature, all the content type info is saved, but not the content_access settings. My feature request is to add features exportables support, so when I save out a feature with a content type, it will save the "Access control" settings I applied to that content type.

** Forums Note **
Comment #26 patch : seem to be applied already in latest 7.x stable and latest 7.x dev

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

wizonesolutions’s picture

Issue tags: +Features integration

Yes, I also ran into this. Have you tried Strongarming "content_access_settings"? I'm not sure if that might help. My need for this isn't great enough to write a patch yet since I can just re-click - but it'd be nice assuming the thing I just mentioned doesn't do it.

Shawn DeArmond’s picture

Yes, that works okay, but what happens is that the $rid is stored, not the role namespace outputted by features. This can be a problem if, say, you enable the feature on a site with a bunch of roles already present. Also, it doesn't let you select different content types, it just grabs the whole thing in one bundle.

It'll work for me okay for my immediate project, but in the future, more official exportables is probably a good idea, with support for features-namespaced roles and the option to limit by content type.

jwilson3’s picture

I'm hitting the exact issue mentioned in #2.

As it stands its impossible to StrongArm a single content type's access control settings to wrap it into a feature, because the single content_access_settings variable stores info for ALL content types :/

The solution that other modules that modify content type definitions, is to add a custom variable for each content type.

Instead of a single content_access_settings we would see something like:

content_access_page
content_access_story
content_access_book
content_access_blog

(using examples of content-type machine names from standard drupal modules).

I suppose the complication comes when you turn on individual node content access. Granted, i havent looked at the node-level content access architecture, so I could be off by a lot in my assumptions here, but I wouldn't want a bunch of references to individual nids stuck into my hypothetical 'content_access_page' variable. For individual node-level access, I'd probably be using a separate table (something that works almost exactly like a cck field db table).

Shawn DeArmond’s picture

Breaking it up to different content types makes sense.

Nodes aren't saved via Features anyway, so there's no reason to have Features save any nid data anyway.

I just noticed that Features also saves Views access information by rid, so at least there is some precedent for using rid.

jwilson3’s picture

Yes, Regarding exporting rid vs. role name vs. role machine name, its all up in the air... and I've seen all three in different places in different types of exports. I would stick with rid since thats what the module currently uses.

Shawn DeArmond’s picture

Unfortunately, the manner in which the setting array is stored is going to make it a little difficult to reconstruct this way. For example, here's a current strongarm export:

<?php
  $strongarm = new stdClass;
  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
  $strongarm->api_version = 1;
  $strongarm->name = 'content_access_settings';
  $strongarm->value = array(
    'view' => array(
      'story' => array(
        0 => 4,
      ),
      'page' => array(
        0 => 3,
        1 => 4,
      ),
    ),
    'view_own' => array(
      'story' => array(
        0 => 2,
      ),
      'page' => array(
        0 => 5,
      ),
    ),
    'per_node' => array(
      'story' => 0,
      'page' => 0,
    ),
    'priority' => array(
      'story' => '0',
      'page' => '0',
    ),
  );
  $export['content_access_settings'] = $strongarm;
?>

But we want it to look more like this:

<?php
  $strongarm = new stdClass;
  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
  $strongarm->api_version = 1;
  $strongarm->name = 'content_access_settings_story';
  $strongarm->value = array(
    'view' => array(
        0 => 4,
    ),
    'view_own' => array(
        0 => 2,
    ),
    'per_node' => 0,
    'priority' => '0',
  );
  $export['content_access_settings_story'] = $strongarm;

  $strongarm = new stdClass;
  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
  $strongarm->api_version = 1;
  $strongarm->name = 'content_access_settings_page';
  $strongarm->value = array(
    'view' => array(
        0 => 3,
        1 => 4,
    ),
    'view_own' => array(
        0 => 5,
    ),
    'per_node' => 0,
    'priority' => '0',
  );
  $export['content_access_settings_page'] = $strongarm;
?>

Is that about right?

If so, only two functions should be changed: content_access_get_settings() and content_access_set_settings() and their input and output should be identical, because we don't want to screw up the api. We also need an update function to convert old settings to new settings.

This can probably all be done with a single new function that does the conversion: content_access_convert_settings($settings).

Shawn DeArmond’s picture

Status: Active » Needs review
FileSize
2.73 KB

Here's a patch that works for me. It passes all the content_access tests, and seems to work as far as I can tell.

Shawn DeArmond’s picture

Status: Needs review » Needs work

Needs an upgrade path.

Shawn DeArmond’s picture

Status: Needs work » Needs review
FileSize
3.89 KB

This is #7 with an upgrade function.

jwilson3’s picture

Awesome Shawn! Just checking out a visual review of the patch, and it looks good, going to test it out here. and report back.

UPDATE: some feedback

This probably needs node-level handling for when a content type gets deleted, to delete the settings for that node type in the variable table.

Scenario:

* create content type 'Laundry',
* setup the content access settings....
* delete the content type,
* uninstall the content_access module,

and BAM!

* you're stuck with dirty Laundry in the variable table, because node_get_types() call in hook_uninstall() doesnt know about the content type at the time of calling.

NOTE this is not actually tested yet, just my hunch ;)

Shawn DeArmond’s picture

Status: Needs review » Needs work

You're absolutely right. I tested it.

The quick-and-dirty fix would probably be something like:

(NOTE: not tested)

<?php

/**
 * Implementation of hook_node_type():
 * Update settings on node type name change.
 */
function content_access_node_type($op, $info) {
  switch ($op) {
    case 'delete':
      variable_del('content_access_settings_'. $info->type);
      break;
    case 'update':
      if (!empty($info->old_type) && $info->old_type != $info->type) {
        $setting = variable_get('content_access_settings_'. $info->old_type, array());
        variable_set('content_access_settings_'. $info->type, $setting);
        variable_del('content_access_settings_'. $info->old_type);
      }
      break;
  }
}
?>

But a "better" solution would probably involve putting it in the content_access_set_settings($settings) function. The problem is that even in in the middle of hook_node_type('delete', $info), node_get_types() DOES include the type that's being deleted.

I'll ponder this for a minute.... and mark it "needs work"

Shawn DeArmond’s picture

Status: Needs work » Needs review
FileSize
4.04 KB

Okay, here's a patch that works. I put a few more lines in the content_access_set_settings() function. It passes simpletest, and it removed the variable when I deleted a content type.

jwilson3’s picture

+++ content_access.module	24 Sep 2010 18:00:13 -0000
@@ -202,7 +209,60 @@ function content_access_set_settings($se
+ * Converts old-style settings to new-style settings, and vice versa.

I'm not totally sure why we would need to convert back to the old style, single-variable format once you've updated to the new style. Could you clarify this use case?

+++ content_access.module	24 Sep 2010 18:00:13 -0000
@@ -202,7 +209,60 @@ function content_access_set_settings($se
+  // Detect whether $settings is new-style or old-style
+  foreach ($types as $name => $type) {
+    if (array_key_exists('content_access_settings_'. $name, $settings)) {
+      $switch = array('new' => 'old');
+    }
+  }

Hmmm... I don't know that running through this code every time you want to get the content access settings is a good idea. I don't know how often this function is queried, but lets assume that when you're loading a view with different content types, its queried on potentially every node. At least, put a break out of the foreach once you detect if its a new style. If this logic block is really necessary, couldn't this be better done by querying the schema version, and running the update script to ensure you're at the new style? Or, you might do this with a single query to see if variable 'content_access_settings' exists instead of scanning through all the content types. If the variable doesn't exist then its new -> old?

Hope my feedback helps.

Powered by Dreditor.

jwilson3’s picture

Regarding your question at the bottom of #11, I'm not sure why you would need to use node_get_types() during delete. Wouldn't this work:

/**
 *  Implementation of hook_node_type().
 */
function content_access_node_type($op, $info) {
  switch ($op){
    case 'delete':
      variable_del('content_access_settings_'. $info->type);
      break;
  }
}
Shawn DeArmond’s picture

This is more of a band-aid to simply support better exportables. You're right, it would be better to have the new-style be the standard. However, that would be a complete API change. Other modules that rely on this API may be expecting the variable to be in the old-style, and it would break. That sort of API change should probably happen, but not until the 6.x-2.0 release.

As to your second point, you're absolutely right, much of this conversion code is probably a little inefficient, and the fact that we have to run the conversion so often is not very performant. If/when the new-style variables become the standard, and we don't need that conversion function anymore, then the future will be bright indeed.

The thing about the conversion function is that it has to convert both ways. The $settings variable that's part of the API (that the rest of the module, and presumably, other modules use) is the old-style, but it stores it as new-stye. That means that content_access_get_settings() has to return the old-style variable (for now).

A more efficient way, I suppose, is to pass a second parameter to the conversion function:
function content_access_convert_settings($settings, $style = 'old')
Then, it doesn't have to auto-detect. That would be more efficient, but the onus would be on the developer to be sure he/she is passing in the right $settings.

Another option would be to have two functions:
function content_access_convert_old_new($settings)
and
function content_access_convert_new_old($settings)

What do you think would be best?

Shawn DeArmond’s picture

Re: #14

Yes, it would work, but I don't know if there are other parts of the API where, if you pass new $settings to the content_access_set_settings() with some node types unset, you'll still have dirty laundry. Basically, my goal was to keep the API as unchanged as possible so I do not raise the ire of module developers who may rely on it.

We can do that for the 2.x release.

fago’s picture

Can't you just use feature module's faux exportable support to set the settings without changing internas? 6.x is long stable now, so I don't like doing such drastic changes now.

jwilson3’s picture

I was just looking at features.api.php yesterday, as another route for implementation of this. One issue I have with going that route is that 1) it varies from the standard way that other modules who modify what could be considered to be a content-type's meta-data by breaking it out into content-type-specific variables, and 2) you'll have to know NOT to export the content_access_settings (in the variable table with strongarm), and to only export the content access settings with the custom Features export support. In this respect, requiring Features API based export to export information stored in the variables table, seems like more of an ugly hack than the current solution.

I think content-type based variables in the variable table (in the long run) is better for consistency with other modules that use the variables table to store configurations. We **could** probably hack up a Features API exportable support, which would require more code and potentially more gotchas, but i think would have the added benefits of not changing the current Content_Access API and not causing any performance hits.

However, before we go seeking in other directions, as 6.x is stable, Fago, would you even consider letting in a solution for this? a la content_access.export.inc

Shawn DeArmond’s picture

I've recently been playing around with hook_features_pipe_component_alter() thanks to #922114: Exporting ds features properly requires strongarm

We may be able to use that hook to be sure that strongarm does NOT export content_access_settings. If it works, that would solve your second issue, @jrguitar21.

Your first issue is more philosophical, and while I agree with you, like @fago said, it's stable. Let's not screw with it if we don't have to... at least not in the middle of a point update. Like I said before, if we're going to be making major API changes, it should be done in 2.x.

fago’s picture

Status: Needs review » Needs work

I think content-type based variables in the variable table (in the long run) is better for consistency with other modules that use the variables table to store configurations.

Might be, but as said in #19 - it's stable, so there won't be so drastic chances just for better consistency.

>We may be able to use that hook to be sure that strongarm does NOT export content_access_settings. If it works, that would solve your second issue, @jrguitar21.
Documenting it would be a way to go too. For sure you can do lots of stuff with strongarm that conflicts with other things.

>However, before we go seeking in other directions, as 6.x is stable, Fago, would you even consider letting in a solution for this? a la content_access.export.inc
I'd be happy to add features integration, but it should build upon the current API.

domidc’s picture

subscribing

MichaelCole’s picture

In D7, saving "content_access_settings" partly works.

View settings are saved
Edit settings are saved for only first content type? Some yes, most no.
Delete settings untested

dboulet’s picture

subscribe

skruf’s picture

subscribe

epieddy’s picture

subscribe

fago’s picture

We don't have to keep the API stable for D7, so I've implemented that for D7 + committed it. Please test.

I've attached the committed d7 patch. It turned out there are not many API changes needed, so backporting the patch to d7 could be an option.

nedjo’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev

The patch does the first part of what's required for features export: provides a per-content-type variable named using the machine name of the content type.

However, as suggested in #2 (and contrary to #5) for features compliance we must use the machine name of the role. With exported rids, we will be assigning access to indeterminate roles on target sites with the obvious accompanying security problems.

mrfelton’s picture

For the issue of rids, Role Export solves this problem by enabling you to give your roles a machine name, which it then generates a unique rid from based on a some kind of hash of the machine name. It makes all modules that export settings that relate to specific roles work nicely together with features and each other.

mrfelton’s picture

Export of settings works well, but the content_access module was not dded to my feature as a dependency. Should this automatically happen when you add one of the content access variables? Not sure, possibly not.

nedjo’s picture

I posted a related handbook documentation page, Exportables and user role IDs in features.

chriscalip’s picture

Issue summary: View changes

Comment #26 patch : seem to be applied already in latest 7.x stable and latest 7.x dev

chriscalip’s picture

I've detected an easy to miss bug but potentially big security risk bug!.. (we'll depending on the circumstance of course) The current #26 patch found in latest stable and dev does not export edit and delete aspects of content access -- It's current iteration only exports view and view own and unfortunately neglects edit own , edit any , delete own , delete any :(

chriscalip’s picture

Added Screenshots showing problem as discuss in comment 32.

chriscalip’s picture

Logic problem located @ file: content_access.module, function content_access_get_setting_defaults
Here's why its a logic problem the purpose of this function is to get sensible default values for the settings, while the records for update,update_own,delete, delete_own are derived from the database ie. the user settings. In an effort to move this forward patch is provided as attached.

/**
 * Defines default values for settings.
 */
function content_access_get_setting_defaults($type) {
  $defaults = array();
  $defaults['view'] = $defaults['view_own'] = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
  foreach (array('update', 'delete') as $op) {
    $defaults[$op] = content_access_get_permission_access(content_access_get_permission_by_op($op, $type));
    $defaults[$op . '_own'] = content_access_get_permission_access(content_access_get_permission_by_op($op . '_own', $type));
  }
  $defaults['priority'] = 0;
  $defaults['per_node'] = FALSE;
  return $defaults;
}
chriscalip’s picture

This patch is an improvement because it retains the original index keys provided by patch comment #26 while fixing the logic that it only provides sensible default of empty instead of using settings from the database.

chriscalip’s picture

chriscalip’s picture

This patch is an improvement because it retains the original array index keys provided by patch comment #26 while fixing the logic that it only provides sensible default of empty instead of using settings from the database. This also removes the overrides from function content_access_admin_settings_submit of not using the form values indexed 'delete', 'delete_own', 'edit' and 'edit_own'. I've tested this patch on my local install I was able to export through features, strongarm, and role_export. I am able to update content access and see edit any, edit own, delete any, delete own are also working.

chriscalip’s picture

Attached Screenshot of devel variable profile of content access strong variable after patch 37 is applied.

jwilson3’s picture

Title: Add support for Features exportables » Content Access support for Features exportables

Just making the title clearer... this has been off the radar for so long.

chriscalip’s picture

Status: Needs work » Needs review

Please review patch proposed by comment #37

a.milkovsky’s picture

Now each content_access setting is stored in separate variable and I can export it with features and strongarm.

But after feature reverting on other Drupal installation content_access settings doesn't work. Because I need to run content_access_mass_update() to rebuild node_access_records.

Please see https://drupal.org/node/2162373

MrPaulDriver’s picture

I'm not sure where we are with this. I find that individual strongarm values are available for each content type but that my content access settings are not deployed with a feature. Is this characteristic of this issue or something different?

fago’s picture

Status: Needs review » Closed (fixed)

However, as suggested in #2 (and contrary to #5) for features compliance we must use the machine name of the role. With exported rids, we will be assigning access to indeterminate roles on target sites with the obvious accompanying security problems.

Yep, that works fine with role export though - so I don't think content access should or can account for that.

-> Setting the issue back to fixed, please re-open new issues for anything left here.

vulfox’s picture

Should this be fixed now?

I just tried with a fresh install of Content Access 7.x-1.2-beta2 and the permissions of the content type are not exported with the content type

Am I doing something wrong?

a.milkovsky’s picture

@vulfox, Content access stores permissions of content type in a separate variable. Use the Strongarm module to add your settings to Features. Also pay attention to mentioned issue in #41.

vulfox’s picture

My bad Strongarm was not enabled fully due to Drush out ot memory.

Although this didn't seem to add that variable automatically like it did for mny others considering that content type?
By design?

a.milkovsky’s picture

Yes, you can consider it as design. You can store permissions and structure settings for the same content type in different features.