🇺🇸United States @partdigital

Account created on 24 June 2011, almost 13 years ago
#

Merge Requests

More

Recent comments

🇺🇸United States partdigital

We're doing something like this on our project. However it is out of the scope of Access Policy so it's not something that will be supported here. With that said, Access Policy is a field so you could try this module https://www.drupal.org/project/field_inheritance .

🇺🇸United States partdigital

I've opened an MR with part of that code removed. (It's what we're using on our project). But I'm open to other approaches as well. For example, perhaps we could be inclusive instead of exclusive. This would be a safer approach.

$override_routes = [
  'entity.node.canonical',
  'entity.node.preview',
  'entity.node.version_history',
];
if ($node->isDefaultTranslation() && n_array($matches[0], $override_routes) {
$variables['title'] = $node->getTitle();
}

https://git.drupalcode.org/project/gin/-/merge_requests/419

🇺🇸United States partdigital

partdigital changed the visibility of the branch 3443218-gin-is-overriding to hidden.

🇺🇸United States partdigital

The behavior is as expected here as the tabs are part of that entity.

Won't this break the messaging for other contrib modules that add custom tabs to the entity? It is a feature that works in Claro, Seven and other admin themes.

Regarding the message: From a UX POV it should appear right before (above) the action buttons in the content area.

It's currently rendering the message the same way as the "Delete" action, it just doesn't have the "This cannot be undone" message. (see screen shot for comparison).

FWIW I think the MR is not the right approach. Do we know exactly which routes we want to only render the title?

🇺🇸United States partdigital

Hi Problue Solutions,

It's going to be a guessing game until I'm able to reproduce it. Are you able to determine at which point in the code the functionality is not working? For example as part of access_policy_entity_presave()? Are you available to connect on Slack? It think it will be easier to diagnose this in real time.

🇺🇸United States partdigital

Thanks for sharing. I noticed that the language is set to en-gb, is that the default language? The "First available" setting will only work for content created in the default language.

You can check that setting here: /admin/config/regional/language

You can see more details here: https://www.drupal.org/project/access_policy/issues/3438598 🐛 Access policy updates get ignored when not using default language Active

If you have multiple policies, another issue that I've occasionally run into is when the weights of all the access policies are set to 0, sometimes their assignment doesn't behave predictably (still under investigation).

As a quick workaround you can:

  1. Go to /admin/people/access-policies/node/settings
  2. Sort the access policies by dragging the handles (it doesn't matter which order).
  3. Click save
  4. Go back to /admin/people/access-policies/node/settings
  5. Sort the access policies in the order that you want.
  6. Click save, this should properly set the weight on the policies.
🇺🇸United States partdigital

Would you be willing to share an export of your access policy?

🇺🇸United States partdigital

Were you able to resolve your issue?

🇺🇸United States partdigital

I would need to see what settings you set for your access policy and permissions. However, make sure that the roles have the "Assign access policy" permission and that "First available" is selected under default policy. Otherwise it won't assign an access policy. This functionality has test coverage so it should all be working as expected.

Feel free to reach out on Slack if you have any questions.

🇺🇸United States partdigital

Hi PhilY,

We're not supporting Search API at this time while we focus on getting 1.0 out. Definitely open to any contributions though!

🇺🇸United States partdigital

Hi Problue Solutions, thanks for reaching out!

Most access rules should work across all entity types that support display modes. Take a look at this documentation to make sure your entity type is fully supported.

Also, if you're having any issues with access rules you can also create your own. Take a look at this documentation for an overview.

🇺🇸United States partdigital

Update description.

🇺🇸United States partdigital

Add more details about custom entity types.

🇺🇸United States partdigital

Change page location.

🇺🇸United States partdigital

Change weight

🇺🇸United States partdigital

I spent some more time investigating this I noticed is that, in some cases, the field controlling access can still be visible on translated pages, even if that field isn't translatable. When authors change the value of that field that can cause that field and access policy to become out of sync.

For example:

  1. Create a new paragraph
  2. Click the "Private" checkbox, this will make the content private. The "Private" field is not translatable.
  3. Create a new French version of that paragraph.
  4. The "Private" checkbox is still visible on the translation.
  5. When an author clicks the checkbox the access policy is not updated.

Does this sound similar to the issue that you're running in to?

I'll add a change so that fields controlling access are only visisble on the default language. In the meantime, a quick fix for this is to make sure that "Hide non translatable fields on translation forms" is checked.

  1. Go to /admin/config/regional/content-language
  2. Scroll down until you see translation settings for paragraphs.
  3. Click "Hide non translatable fields on translation forms"
🇺🇸United States partdigital

Would you be willing to share some more details about your policy and steps to reproduce? I'd like to see if I can reproduce it as well.

One thing I should mention is the way that access policy handles assignment. The "Dynamic" selection mode will only assign the policy if the field value has changed between revisions. Do you think that could be a factor as well?

If so, in the latest dev version I've added the ability assign policies "on save" instead of "on change", to try it out do the following:

  1. Update to the latest dev version.
  2. Create a new selection strategy plugin (see below).
  3. Enable that Selection mode for paragraphs

<?php
namespace Drupal\access_policy\Plugin\access_policy\SelectionStrategy;

use Drupal\Core\Entity\EntityTypeInterface;

/**
* On save selection strategy.
*
* @SelectionStrategy(
* id = "on_save",
* label = @Translation("On save"),
* description = @Translation("On save, access policies are dynamically assigned to entities based on selection rules."),
* weight = 0,
* )
*/
class OnSaveSelection extends SelectionStrategyBase {

/**
* {@inheritdoc}
*/
public function defaultOptions() {
return [
'dynamic_assignment' => 'on_save',
'enable_selection_page' => FALSE,
'show_operations_link' => FALSE,
'enable_policy_field' => FALSE,
'allow_empty' => FALSE,
];
}

/**
* {@inheritdoc}
*/
public static function isApplicable(EntityTypeInterface $entity_type) {
return TRUE;
}

}

🇺🇸United States partdigital

Hi gmarus, thanks for reaching out!

There a few assumptions that access policy makes:

  • The access_policy field is not translatable.
  • It will only determine the policy based on the Default translation.

This is to prevent translations from having different policies.

The condition $entity->language()->isDefault() was added to prevent selecting a policy against translated field values. For example, let's say the original language has the "Sales" department, but the French translation doesn't have a department. Because the access_policy field is not translatable that would remove the policy entirely.

You can see a test case here covering this use case: https://git.drupalcode.org/project/access_policy/-/blob/1.0.x/tests/src/...

To use access policy predictably I recommend only using non-translatable fields with selection rules. I'm definitely open to investigating language specific policies in future versions.

🇺🇸United States partdigital

Glad to hear you were able to update the module!

Since it doesn't seem any code changes are necessary I'll close this as "Works as designed."

🇺🇸United States partdigital

Ah ok I hadn't realized that you weren't using drush. That's good to know for future updates. I just it ran the update against update.php and it seemed to work as well.

In regards to the composer update did you try it with:

composer update drupal/access_policy --with-all-dependencies

In some cases I might also do it like this:

composer require drupal/access_policy:1.0.0-beta7

Note that I've never seen composer used like composer update drupal.access_policy. When I ran composer update drupal/access_policy it updated successfully.

Here is a comparison of the messages between the two commands:

composer update drupal.access_policy --with-all-dependencies

Gathering patches from patch file.
> DrupalProject\composer\ScriptHandler::checkComposerVersion
Loading composer repositories with package information
Package "drupal.access_policy" listed for update is not locked.
Updating dependencies
Nothing to modify in lock file
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
Package nabil1337/case-helper is abandoned, you should avoid using it. Use marcusball/case-helper instead.
Package webmozart/path-util is abandoned, you should avoid using it. Use symfony/filesystem instead.
Generating autoload files
    Skipped installation of bin artifact for package lastcall/artifact.sh: file not found in package
96 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> DrupalProject\composer\ScriptHandler::createRequiredFiles
> DrupalProject\composer\ScriptHandler::compileComposerServices
Run "composer audit" for a full list of advisories

composer update drupal/access_policy --with-all-dependencies

Gathering patches from patch file.
> DrupalProject\composer\ScriptHandler::checkComposerVersion
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 0 installs, 28 updates, 0 removals
  - Upgrading doctrine/lexer (2.1.0 => 2.1.1)
  - Upgrading drupal/access_policy (dev-1.0.x ba6a7ee => dev-1.0.x 3582651)
  - Upgrading egulias/email-validator (3.2.6 => 4.0.2)
  - Upgrading mck89/peast (v1.16.0 => v1.16.1)
  - Upgrading phpdocumentor/type-resolver (1.8.0 => 1.8.2)
  - Upgrading phpstan/phpdoc-parser (1.25.0 => 1.26.0)
  - Upgrading symfony/console (v6.4.3 => v6.4.4)
  - Upgrading symfony/dependency-injection (v6.4.3 => v6.4.4)
  - Upgrading symfony/error-handler (v6.4.3 => v6.4.4)
  - Upgrading symfony/http-foundation (v6.4.3 => v6.4.4)
  - Upgrading symfony/http-kernel (v6.4.3 => v6.4.4)
  - Upgrading symfony/mailer (v6.4.3 => v6.4.4)
  - Upgrading symfony/polyfill-ctype (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-iconv (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-intl-grapheme (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-intl-idn (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-intl-normalizer (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-mbstring (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-php72 (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-php80 (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-php81 (v1.28.0 => v1.29.0)
  - Upgrading symfony/polyfill-php83 (v1.28.0 => v1.29.0)
  - Upgrading symfony/process (v6.4.3 => v6.4.4)
  - Upgrading symfony/serializer (v6.4.3 => v6.4.4)
  - Upgrading symfony/string (v6.4.3 => v6.4.4)
  - Upgrading symfony/validator (v6.4.3 => v6.4.4)
  - Upgrading symfony/var-dumper (v6.4.3 => v6.4.4)
  - Upgrading symfony/var-exporter (v6.4.3 => v6.4.4)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 28 updates, 0 removals
  - Syncing drupal/access_policy (dev-1.0.x 3582651) into cache
Gathering patches from patch file.
Gathering patches for dependencies. This might take a minute.
  - Upgrading symfony/polyfill-ctype (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-php80 (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-php83 (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-mbstring (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/http-foundation (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/var-dumper (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/error-handler (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/http-kernel (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/polyfill-intl-normalizer (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-intl-grapheme (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/string (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/console (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading doctrine/lexer (2.1.0 => 2.1.1): Extracting archive
  - Upgrading symfony/validator (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/serializer (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/process (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/polyfill-iconv (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-php72 (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/polyfill-intl-idn (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading symfony/var-exporter (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/dependency-injection (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading mck89/peast (v1.16.0 => v1.16.1): Extracting archive
  - Upgrading egulias/email-validator (3.2.6 => 4.0.2): Extracting archive
  - Upgrading drupal/access_policy (dev-1.0.x ba6a7ee => dev-1.0.x 3582651): Checking out 3582651d47 from cache
  - Upgrading phpstan/phpdoc-parser (1.25.0 => 1.26.0): Extracting archive
  - Upgrading symfony/mailer (v6.4.3 => v6.4.4): Extracting archive
  - Upgrading symfony/polyfill-php81 (v1.28.0 => v1.29.0): Extracting archive
  - Upgrading phpdocumentor/type-resolver (1.8.0 => 1.8.2): Extracting archive
Package nabil1337/case-helper is abandoned, you should avoid using it. Use marcusball/case-helper instead.
Package webmozart/path-util is abandoned, you should avoid using it. Use symfony/filesystem instead.
Generating autoload files
    Skipped installation of bin artifact for package lastcall/artifact.sh: file not found in package
96 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> DrupalProject\composer\ScriptHandler::createRequiredFiles
> DrupalProject\composer\ScriptHandler::compileComposerServices
🇺🇸United States partdigital

@gilbertdelyon one thing I forgot to ask earlier. Did you run drush updb? That will update all your access policies with the new operations.

Here are the steps that I went through to upgrade one of our projects to beta7.

composer update drupal/access_policy 
drush cr
drush updb

@rishabjasrotia which tests are you referring too? All tests are currently passing.

🇺🇸United States partdigital

Thank you.

Unfortunately I still can't reproduce it.

It's a very odd error because nothing changed in regards to the 403 http response. It sounds like it may be another issue with a mysterious cause unique to your environment (similar to #3419046 🐛 Undefined context error when user resets password Fixed ). Perhaps it's conflicting with a contrib module? Are you able to reproduce the error on a vanilla Drupal 10 site?

🇺🇸United States partdigital

Would you mind sharing any access policies that you have?

🇺🇸United States partdigital

Hi gilbertdelyon, did you clear the cache?

🇺🇸United States partdigital

The MR has been merged. To add support for a custom entity type, your entity type must:

  • Be a content entity type
  • Have a valid entity id key
  • Have a view builder class
  • Have a route for the field_ui_base_route property
  • Support Bundles

Here is an example expressed in terms of annotation:

/**
 * @ContentEntityType(
 *   id = "example",
 *   label = @Translation("Example"),
 *   handlers = {
 *     "view_builder" = "Drupal\example\ExampleViewBuilder",
 *   },
 *   entity_keys = {
 *     "id" = "id",
 *   },
 *   bundle_entity_type = "example_type",
 *   field_ui_base_route = "entity.example.edit_form",
 * )
 */
class ExampleEntity extends ContentEntityBase {

}
🇺🇸United States partdigital

I've opened an MR. I still want to add some automated tests but this will probably be the final production code.

To summarize the changes, in order to Integrate with access policy, your entity type must

  • Be a content entity type
  • Support Bundles
  • Have a view builder class
  • Have a route for the field_ui_base_route property

If you want to support Manual selection mode:

  • You need to have a canonical link template.
  • Have a local task defined for the route associated with that link template.

I tested this on core and contrib including:

Comments
Unfortunately I had to disable support for comments because of this issue: https://www.drupal.org/project/drupal/issues/2879087 📌 Use comment access handler instead of hardcoding permissions Needs work

Profile
This supports access policy, however it only supports Dynamic mode because no local tasks have been defined for that entity. There is an issue to address it: https://www.drupal.org/project/profile/issues/3139127

🇺🇸United States partdigital

partdigital changed the visibility of the branch 3421025-how-to-use to hidden.

🇺🇸United States partdigital

I spent some more time investigating this, specifically finding a way to relax the entity type constraints while also avoiding unpredictable behavior caused by entity types provided by contrib. The original culprit was the Crop module which triggered fatal errors. You can see the issue here: https://www.drupal.org/project/access_policy/issues/3384483 🐛 Unable to run access_policy_update_9001 Fixed .

Here is a patch with some changes that opens up access policy to other entity types. I removed the revision requirement and copied some logic from the Display modes pages. This seemed to make a lot of sense in this context. All my automated tests passed and the crop entity was still excluded. Yay!

I still need to add tests for non-revisionable entity types but this is the direction that I would go in. Please feel free to give it a try and let me know if you run into any issues.

🇺🇸United States partdigital

I had considered adding a hook like hook_access_policy_entity_types_alter($entity_types). However, I decided against it (for the time being) because Access Policy makes assumptions based on those features and allowing developers to bypass those could lead to some unpredictable bugs which I just don't have the bandwidth to support.

I can say that for your use case, it's safe to add a canonical link to your entity type. You could even just have it point to the edit form. For example, this is how media does it.

 *   links = {
 *     "canonical" = "/media/{media}/edit",
 *   }

To give some context, I added that requirement so that it would support both Dynamic and Manual selection modes. If want to use Manual selection mode you'll need to have a canonical link.

In regards to making revisions (and bundles) optional by adding an API. That is unexplored territory and each will need its own issue and test coverage. The access_policy field for example is a base field that supports revisions; would it still behave properly if it was added to an entity without revisions?

So while I completely understand the motivation to add a hook of some kind, there's simply a lot more that needs to be investigated first.

But definitely apply a local patch to the module and let me know what issues you run into. I'd be very curious to learn what you find.

🇺🇸United States partdigital

Correct, the type property on the Access policy entity doesn't do anything anymore. However, it was left in to support the upgrade process. For example, we have projects with their own access policy type and it would have broken all those sites if that was removed.

That property, along with all the AccessPolicyType plugins, will be removed in the next release.

🇺🇸United States partdigital

General text updates.

🇺🇸United States partdigital

Move operations image below heading.

🇺🇸United States partdigital

Access policy beta7 updates.

🇺🇸United States partdigital

Add access rule and selection rule steps.

🇺🇸United States partdigital

Access policy beta7 updates.

🇺🇸United States partdigital

Access policy beta7 updates.

🇺🇸United States partdigital

Access policy beta7 updates.

🇺🇸United States partdigital

Access policy beta7 updates.

🇺🇸United States partdigital

Access policy beta7 changes.

🇺🇸United States partdigital

Hi frob!

In order to support a custom entity type, make sure that your entity type has the following:

  • Is a content entity type
  • Has a numeric id key
  • Supports bundles
  • Has a canonical link template
  • Is revisionable

Expressed in terms of the annotation these are the keys that you need to integrate with access policy. (Note: other keys have been removed for brevity).

/**
 * @ContentEntityType(
 *   id = "example",
 *   label = @Translation("Example"),
 *   revision_data_table = "example_field_revision",
 *   entity_keys = {
 *     "revision" = "vid",
 *   },
 *   bundle_entity_type = "example_type",
 *   links = {
 *     "canonical" = "/example/{entity_id}",
 *   }
 * )
 */
class ExampleEntity extends ContentEntityBase {

}
🇺🇸United States partdigital

Glad to hear the patch worked! I'll commit that and then mark this as resolved :D

I was referring to something along the lines of Step #7 of the Restrict Content by Department tutorial . However, it sounds like you're not doing that.

🇺🇸United States partdigital

Are you by chance restricting taxonomy terms with an Access Policy? In particular, Groupes Utilisateurs? If so, that may explain why CurrentUser:;getValue(); is being called in the first place.

🇺🇸United States partdigital

I appreciate the feedback.

I'm definitely going to write some more tutorials. One or two more for common use cases as well as a collection of tutorials on how to use the API. There is also a slack channel #access-policy-module where anyone can submit questions. I'm also available on #support.

I'd say let's leave this issue open as a general discussion where anyone can talk about the pain points of learning Access Policy. So some general questions I might have (for anyone reading this).

  • Do you use the Tours module? Would that be helpful?
  • What use cases in particular would you like to see a tutorial on?
  • Is there anything in the UI that is particularly confusing?
🇺🇸United States partdigital

Here is a patch to address the fatal error. I'm still curious why this would be called in this context but AccessRuleArguments are designed to work without the context so it's a good thing to add anyway.

Let me know if this resolves your issue.

🇺🇸United States partdigital

I added a new subtheme based on bartik but unfortunately I still couldn't reproduce it. Very mysterious.

My hunch is that it's related somehow to hiding the fields on the user's profile. I would try disabling the code and see if it stops happening.

Start with access_policy_entity_field_access() in access_policy.module and work from there.

Also, what over fields do you have on the user?

🇺🇸United States partdigital

Thanks for the step-by-step, that is very helpful!

Unfortunately I still can't reproduce it. Would you be willing to share an export of the access policies? Maybe there's something about the configuration that I'm not thinking of.

1. Go to /admin/config/development/configuration/single/export
2. Select Configuration Type > Access Policy
3. Select the access policy you want to export.

🇺🇸United States partdigital

H gilbertdelyon

Nice catch! Unfortunately I haven't been able to reproduce it either. Though, looking at some code I can see how theoretically it could happen.

This can happen when AccessRule::getValue(); is called before the context is set.

For example, it should happen like this:

$access_rule->setContext(ExecutionContext::create('view', ['user' => $this->currentUser]);
$access_rule->getValue();

If it never calls setContextExecutoinContext it could trigger that error. Are you able to do some debugging and isolate where $access_rule->getValue(); is being called?

🇺🇸United States partdigital

I've opened a discussion thread around groups, I've received a few related requests so I thought it might be useful to consolidate ideas into something cohesive.

https://www.drupal.org/project/access_policy/issues/3419012 🌱 Discussion: Access policy group enhancements Active

🇺🇸United States partdigital

I've opened a discussion thread around groups, I've received a few related requests so I thought it might be useful to consolidate ideas into something cohesive.

https://www.drupal.org/project/access_policy/issues/3419012 🌱 Discussion: Access policy group enhancements Active

🇺🇸United States partdigital

I've opened a discussion thread around groups, I've received a few related requests so I thought it might be useful to consolidate ideas into something cohesive.

https://www.drupal.org/project/access_policy/issues/3419012 🌱 Discussion: Access policy group enhancements Active

🇺🇸United States partdigital

I think one of the biggest issues we're are running into is that Taxonomy terms are a bit of a misfit for creating groups of users. They are great for categorizing content but miss some workflow features for handling users.

I had been considering a few approaches for this.

Access Policy Group module.
This is probably the most work but also has the most potential. For the sake of purity it might make sense to make it as another contrib module since Access Policy itself doesn't have much of an opinion.

  • It would be a new "Group" content entity type.
  • It would very simple and share a lot of features with Taxonomy terms such as nesting and weights. It's essentially just another entity that access policy can talk to.
  • You use it by adding entity reference fields to the Node and User like with taxonomy terms.
  • The group would come with some operations like Manage members, Add member etc. These essentially are just forms for setting field values on the user.
  • The Access Policy Group module would ship with its own access rules so in that way it can be more more prescriptive than taxonomy terms.
  • The access part of this would already be mostly handled by access policy. This would primarily be a module with workflow enhancements.
  • A new Group content entity type would clear the runway for features more geared to user enrollment.

Contribute to Views bulk edit
Using views to create group management pages could be very powerful. The main limitation is how to add members to that group from within that context. Perhaps Views bulk edit could help?

🇺🇸United States partdigital

HI MegaKeegMan,

I agree, the UI can be tricky to comprehend when first using it. Definitely open to feedback on how to improve it. Feel free to suggest any other changes and submit a patch to get credit.

I had interpreted checkmarks to mean that rules CANNOT apply to those operations.

This is very interesting and you raise a good point; a checkmark might mean something else for different people. Could you elaborate more? I'd be very interested to hear how you came to that assumption. Do you think another symbol may be more appropriate?

One feature that I'm currently working on is the ability to configure operations for each access policy. This means that the concepts of "Group", "Private" etc will be going away and you can configure it any way you want. This should help with the discoverability/learnability of the user interface as well as provide a useful feature. This will be with released with beta7.

Here is a sneak peak.

I'm also considering using Drupal tours which can guide users through the user interface right from within Drupal.

In the meantime, if you haven't seen it yet, I highly recommend watching this video. It gives a demo of the UI as well discusses some high level concepts which should help contextualize everything.

https://www.youtube.com/watch?v=Dzsj8vTQf0E.

🇺🇸United States partdigital

Hi mlncn!

This kind of functionality has come up a few times in slightly different versions. You can see these issues here:

I think one of the biggest issues we're are running into is that Taxonomy terms are a bit of a misfit for creating groups of users. They are great for categorizing content but miss some workflow features for handling users.

I had been considering a few approaches for this. The one that I like the most is a kind of "Access Policy Group" module. However, that is also the most work.

  1. It would be a new "Group" content entity type.
  2. It would very simple and share a lot of features with Taxonomy terms such as nesting and weights. It's essentially just another entity that access policy can talk to.
  3. You use it by adding entity reference fields to the Node and User like with taxonomy terms.
  4. The group would come with some operations like Manage members, Add member etc. These essentially are just forms for setting field values on the user.
  5. The Access Policy Group module would ship with its own access rules so in that way it can be more more prescriptive than taxonomy terms.
  6. The access part of this would already be mostly handled by access policy. This would primarily be a module with workflow enhancements.

A new Group content entity type would clear the runway for features more geared to user enrollment.

On a related note; I'm currently working on making operations (view, edit, delete) pluggable. So with an "Access Policy Group" module we could also add operations like "Add member" and it would easily integrate with access policy. In fact, each operation is context aware so it will only show operations that are applicable to their respective entity type.

What do you think?

🇺🇸United States partdigital

Did you try something like this?

Department policy

  • Access rule: Department taxonomy term, empty value is set to deny
  • Selection rule: Department field is not empty
  • Selection set: Restricted

Location policy

  • Access rule: Location taxonomy term, empty value is set to deny
  • Selection rule: Location field is not empty
  • Selection set: Restricted

If no value is provided for the Location field or the Department field it won’t assign any policy and it will be accessible to everyone.

Yes, but for the node fields I used "filter by an entity reference view" to apply some restrictions so I think this breaks the rules in the access policy.

I've been able to reproduce this and will open a new ticket to address it.

🇺🇸United States partdigital

I've upgraded the module to dev, but I'm facing another issue, now I can't see all needed rules for all fields. I just can find 2 of them.

I pushed up a change in beta6 that limited entity reference access rules to only fields that configured identically. For example, the Department taxonomy term field needs to have the same bundles selected for both the user and node fields. I added this in because it was adding a lot of fields that didn't do anything otherwise. Did you take a look at your entity reference fields to make sure they had the same bundles selected?

The ignore issue will require some more investigation. In the meantime there are a few workarounds that you can try.

  • Break up your access rules across two access policies and group them into a Selection set. This allows you to assign two policies at the same time using OR logic. This is will have the same effect and should resolve the issue.
    • You can create your own AccessRuleQueryHandler and modify the query.

For example, you can modify the annotation of the access rule and replace it with your own handler.


function mymodule_access_rule_alter(&$definitions). {
  $definitions['entity_field_entity_reference']['handlers']['query_alter'] = '\Drupal\mymodule\AccessRuleQueryHandler\MyQueryHandler';
}
🇺🇸United States partdigital

Hi Odai,

This sounds relatively similar to a fix that was pushed last week. Does it still happen if you upgrade to the latest dev version?

🇺🇸United States partdigital

Change "Apply policy to listing pages" to "Apply access policy to queries"

🇺🇸United States partdigital

Changed "apply policy to listing pages" to "Apply access policy to queries"

🇺🇸United States partdigital

Minor cleanup.

🇺🇸United States partdigital

Hi MegaKeegMan

This is by design. Public policies are limited to just permissions and not access rules. The idea being that, in most cases, only internal users will be allowed to create public content and they will have their own role (e.g Employee).

Each policy type (Public, Private, Group etc) is a plugin so you can define your own if you like. In your case it might look like this:

/**
 * Public access policy type with access rules.
 *
 * @AccessPolicyType(
 *   id = "public_with_rules",
 *   label = @Translation("Public with access rules"),
 *   weight = -3,
 *   operations = {
 *     "view" = { } 
 *     "view all revisions" = {
 *         "permission" = true,
 *         "rules" = true,
 *      },
 *     "update" = {
 *         "permission" = true,
 *         "rules" = true,
 *      },
 *     "delete" = {
 *         "permission" = true,
 *         "rules" = true,
 *      },
 *     "view unpublished" = {
 *         "permission" = true,
 *         "rules" = true,
 *      },
 *     "manage access" = { } 
 *       "rules" = true,
 *      },
 *   }
 * )
 */
class PublicWithAccessRules extends AccessPolicyTypeBase {

}

Note that for each operation you can define how you want to restrict it. You can use permissions or rules or both (or neither).

Another approach you can do is to simply use the Group policy type, grant all users the view operation and exclude the View operation from the access rules.

🇺🇸United States partdigital

kristiaanvandeneynde, I was attempting to try out the Access Policy API in Drupal 11 as part of an investigation into integrating it into the Access Policy module . Even though the service collector is defined in core.services.yml I noticed that addAccessPolicy is never actually called. It looks like this is because it's never retrieved by the container except in the automated tests. I assume that's what this issue is for?

Is this API currently dormant in Drupal 11? If so, would it be worth mentioning that in the documentation This way developers don't go down a rabbit hole only to discover it's not ready?

Unless of course I'm missing something entirely which in that case, open to any suggestions.

🇺🇸United States partdigital

Glad you were able to resolve the issue!

For other questions like this feel free to reach out in slack as well. I'm active in #support and #access-policy-module.

https://www.drupal.org/slack

🇺🇸United States partdigital

Hi gilbertdelyon,

The current supported approach for this is to add access policies for the taxonomy terms themselves. Take a look at the Step 7 of the tutorial Group content by department.

🇺🇸United States partdigital

Would someone performing these bulk operations on group members require the permission to change the values in the user field?

Apologies for the late reply, I'm currently on holiday.

In your custom action you would be using the entity_autocomplete field widget so it's up to you how you want to handle the permissioning of that action. As far as which terms are available to that user, that should automatically be filtered for you as long as you've set up access policies for the taxonomy terms.

🇺🇸United States partdigital

Hi jrochate, thanks for asking!

I'm planning on incorporating the API into Access Policy 2.0 after 10.3 is released.

The Access Policy API actually addresses only one of the issues that the Access Policy module has solved. So integrating the API will be more akin to a refinement of one of its subsystems rather than a replacement for the entire module. For example, the Access Policy API doesn't have any opinion about how or where to store access information, the Access Policy module on the other hand follows the Attribute-Based Access Control (ABAC) paradigm where it uses Drupal fields for handling access.

As far as integration goes this will likely be an internal system so it will be integrated behind-the-scenes. Users of the Access Policy module may not even notice a difference between 1.0 and 2.0. Except for perhaps less clutter on the permissions page.

I talk briefly about the differences between the API and Access Policy if you're interested to learn more :D
https://youtu.be/Dzsj8vTQf0E?si=6moFjU63rC8YUgUT

🇺🇸United States partdigital

Ah ok I think I understand now. I hadn’t considered this use case so thanks for that!

A few suggestions:

  • You only need to have one “Group” field on the node. The “Group editable” and “Group viewable” on the user should be enough because they're already controlling operations.
  • Have you tried breaking up the policy into two (Group and User access policies) and putting them in a Selection set? This would allow you to toggle user/group access for each node. It's not strictly necessary but it might be nice user experience.

Ideally (for me) group access would be managed centrally, and not from a user reference field.

There’s currently nothing built into Access policy to do this. However, you could do the following:

  • Create a new view that shows the Group taxonomy terms.
  • When a user clicks a term it will show another view that lists the members of that group.
  • Install the Views bulk operations module and write a few custom action plugins (e.g Add member, Remove member).

We did something similar to this on one of our projects and it worked well for us.

🇺🇸United States partdigital

Hi MegaKeegMan thanks for reaching out!

You should be able to do this with access policy, this sounds like a combination of these two tutorials:

If you haven't tried them yet I recommend going through them.

For your use case it sounds like two roles (Content manager and Contributor) and two access policies (Public and Private)

Public content
Viewable to everyone but only editable to users in a group.
Follow the "Group content by department" tutorial above. Only change you will need to make is to grant all roles "view" access.

Private content:
Editable by original author, only viewable to users in a group OR users are are explicitly granted access.

Follow the "Private content" tutorial

Then add additional access rules with the OR validation operator. You'll also need to adjust the operation constraints. Note, in order to add these access rules you'll need to add fields to the node and user.

  • Compare Group with user
  • Allowed users field has reference to current user

Definitely worth giving a try. Let me know if you run into any issues.

🇺🇸United States partdigital

Yes that code will work with media as well. If you want to do this dynamically you can use this method to fetch all the entity types that have access policies.

\Drupal::service('access_policy.information')->getAllEnabledEntityTypes();
🇺🇸United States partdigital

Hi gilbertdelyon, thanks for reaching out!

That is a clever workaround! Only risk with that approach is that it will assign the access policy based on the currently logged-in user. If you performed that action with a role that wasn't allowed to assign the "department" policy for example, it wouldn't change the policy, even if the department field had a value.

This has been on my radar for a while, perhaps I can address this with a custom "Save default access policy" action? This would account for the original author.

You can also achieve the same result with this code added to an update hook. Note that if you have a lot of nodes with missing policies you probably want to put this into a batch.

 $entityTypeManager = \Drupal::entityTypeManager();
  $selectionManager = \Drupal::service('access_policy.selection');
  $nids = $entityTypeManager->getStorage('node')->getQuery()
    ->accessCheck(FALSE)
    ->condition('access_policy', NULL, 'IS NULL')
    ->execute();

  $nodes = $entityTypeManager->getStorage('node')->loadMultiple($nids);

  foreach ($nodes as $node) {
    // Get the original author. This is necessary because different authors may
    // have access to different access policies.
    $owner = $node->getOwner();
    $policies = $selectionManager->getDefaultPolicy($node, $owner);
    if (!empty($policies)) {
      $node->set('access_policy', $policies);
      $node->save();
    }
  }

🇺🇸United States partdigital

I also ran into this issue when expanding/collapsing paragraphs:

  • Drupal Core: 10.1.6
  • Paragraphs: 1.16
  • H5P: 2.0.x

It seems to be caused by the submitted form values not being properly formatted upon Expand/Collapse. A quick fix for this was to simply remove some code in H5PWidgetBase::massageFormValues.

public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {

   // Remove this condition.
   if (!$form_state->isValidationComplete()) {
      return $values;
    }

    // ... Code removed for brevity ...

    // The condition is preventing this method from running which properly formats the code. 
      $return_values[$delta] = $this->massageFormValue($value['h5p_content'], $delta, $do_new_revision);
    }

    return $return_values;
}

I've attached a patch for this however since it's removing some code there is the possibility of introducing a regression. It could definitely use some extra review/testing.

🇺🇸United States partdigital

@nilubol

I spent some more time investigating approaches for this, and in most cases there were trade-offs that weren't ideal.

  • Splitting query settings for each access policy - I gave this a try and was able to get something working without too much refactoring. However the experience wasn't ideal because now you only had policies that applied to entity reference fields where it might also need to apply to views in other contexts.
  • Using the "use" operation - This is similar to splitting query settings, the difference being it varies per user. For example, some users will have entity reference fields restricted while others won't. This is probably the most useful use case but unfortunately I ran into a snag with Drupal core. It really expects you to be using the "view" operation in entity reference fields. Because of that I was getting all sorts of validation errors. Take a look at ValidReferenceConstraintValidator::142

This brings me to one more option, one that is starting to grow on me.

Provide two query options.

  • Automatic - This applies to all queries automatically, it's the most aggressive yet the easiest to setup (the current approach)
  • Manual - All views, entity reference fields, and queries need to have access_policy query alter manually applied to them.

Manual essentially means no queries will be restricted by default.

  • You'll need to add a new "Access" filter to each view that you want to be constrained by access policy.
  • For entity reference fields, you'll need to select an "Access controlled" option from the Reference method setting of each entity reference field.
  • For all other queries, you can write some code to add a new access_policy tag to each query to tell it to allow access policy to alter that query.

By doing it this way you'll have much more fine-grained control of which queries are controlled by access policy. It'll also help with performance.

Production build 0.69.0 2024