Can we change workbench_moderation_states_next() to

  1. accept a full node object instead of just a type string, and
  2. offer a hook so that other modules can manipulate the list of available states based on the properties of the node?

I'll roll a patch here in just a minute to show what I have in mind...

Comments

muriqui’s picture

Status: Active » Needs review
StatusFileSize
new4.82 KB

Changes included in the patch:

  • On workbench_moderation_states_next(), changes the $node_type parameter to $node (with logic to allow it to still accept a node type string), adds a new drupal_alter hook, and adds a "global $user" statement that I think was previously needed but missing.
  • Documents the new hook in the API.
  • Changes existing calls to workbench_moderation_states_next() to pass the full node where possible (all except for the call in workbench_moderation_form_alter()).
stevector’s picture

Thanks for the interesting idea muriqui.

What do you think is the use case for this hook? That will make the patch easier to test.

muriqui’s picture

Hi Steve,
I see this being handy for two cases:

  1. Adding additional workflow restrictions based on the properties of the node. There's a demonstration use case included in the patch's changes to workbench_moderation.api.php, i.e. preventing users who normally have permission to moderate nodes from "needs review" to "published" from directly publishing nodes that they personally authored. Another example might be to allow collaborative work on an article between copy editors and media asset providers, such as allowing someone to write a magazine article and submit it for copy editing, but not allow it to be published until an imagefield is populated by the photography department to provide the lead photo.
  2. Modules implementing access controls. We already have alter hooks in _workbench_moderation_access() to modify the default access controls by op, but workbench_moderation_states_next() is used in other places as an access control, so it seems like a natural extension of the concept. I have a module in the works that will exercise this. I could also see someone writing integrations with OG, TAC, content_access, etc.; basically, anywhere that you'd want to control access to workflow states based on anything beyond basic role membership.
stevector’s picture

StatusFileSize
new59.7 KB

Thanks for the explanation muriqui. I like where you are going with this. Before releasing Workbench we discussed a similar use case. We discussed a hypothetical site that would need the states of "editorial review," "PR review" and "legal review." I pointed out that for some clients this might not be a linear process and that those three states do not follow a specific order. In some cases it may only matter that those three departments have reviewed a node and "signed off." I think with this hook a site could set up arbitrary rules like that so a node can't be published without entering those states or perhaps those are just separate checkboxes as fields.

I think I just rephrased everything you said but I want to make sure we're on the same page.

What I like about your approach is that the mechanism is arbitrary and as you said, OG, TAC, even Workbench Access could hook in.

However there could be a downside to the arbitrary nature. I would be concerned if all of those modules implemented completely separate UIs for controlling transition states. I'd like to look into using the access functionality in CTools allow or deny a transition. Attached is a screenshot that might help.

I have used CTools access plugins a lot with Panels. I have even written some custom ones. However, I don't know what is necessary to do this integration I'm suggesting.

One of the reasons I like this is that it requires Organic Groups to write no new code at all. OG already has CTools access plugins so if we got this working OG would integrate immediately with no unique attention.

How does this sound muriqui? Have I taken your idea in a completely different direction? I think if this hook got into WB Moderation then all the CTools integration could be a separate module if we want to keep WB Moderation simple.

muriqui’s picture

I think I just rephrased everything you said but I want to make sure we're on the same page.

Sounds like we're on the same page. :)

I think if this hook got into WB Moderation then all the CTools integration could be a separate module if we want to keep WB Moderation simple.

My vote would be to keep the hook and any CTools integrations separate. A hook provides an easy, low-level way to alter the transition rules, which I think would complement the existing access_alter hook nicely, especially given that there are a couple of places where the states_next function is used as an implicit access control, without triggering the other access functions. For modules looking to leverage WB Moderation, that may be all that's needed. Could a CTools plugin then simply implement the new hook to extend that functionality to other CTools-enabled modules? You'll have to forgive me here... My understanding of CTools is pretty basic at this point.

stevector’s picture

Yes idea behind the CTools integration is that OG or any other module wouldn't need to do anything specific to Workbench. CTools access plugins accept arbitrary "contexts" and other variables if necessary and then return TRUE or FALSE. So there is an OG CTools access plugin (at least there was in D6) that takes as the "context" of a node, and I think the context of a user (or it just uses the current user), and then returns TRUE or FALSE for if that user is in that group node.

I have used that plugin to control access to a panels page. The path to that page was something like "example.com/foo/bar/%nid" So between Panels and CTools that %nid was converted to a node object and that node object was passed to an arbitrary number of CTools access plugins one of which evaluated whether the current user belonged to the group and returned TRUE or FALSE accordingly.

The important part is that the OG CTools access plugin doesn't need to know or care if it is controlling access to a page like foo/bar/%nid or is control access to the next state of workbench moderation.

So to answer your question, other modules could provide a CTools access plugins or they could implement the WB Moderation hook directly.

muriqui’s picture

OK, that makes sense. Thanks. Then should we open up another issue so that the CTools plugin can be worked on separately? Or should that discussion wait until a decision is made on committing the hook?

stevector’s picture

Hi again muriqui. The CTools plugin approach would depend on the hook so perhaps the hook first. I'd like the opinion of another Workbench dev.

We got a similar request in #1127524: New permissions

rv0’s picture

Testing the patch in #1

Working nicely for my custom access module

any news on this?

stevector’s picture

I'm sorry this issue hasn't gotten much attention lately. Bug fixes are getting prioritized over new features.

I just marked another issue as a dup of this one: #1190256: Extensibility: Collective /IMC /group moderation; rules for more editors having to decide together

justintime’s picture

Subscribe.

stevector’s picture

I want to get this hook in soon meet the functionality discussed in #1294880: Convert Workbench Moderation records to entities

Muriqui, just a few minutes ago I was moving an issue from Workbench to Workbench Moderation and the autocomplete widget brought up http://drupal.org/project/conditional_roles_workbench_moderation It looks like we're trying to solve a lot of same problems.

Perhaps we can discuss in #drupal-workbench soon.

sreynen’s picture

sreynen’s picture

Hmm. Think I just found a bug in the test system. Trying to submit a completely different patch, somehow ended up here. Disregard.

muriqui’s picture

It looks like we're trying to solve a lot of same problems.

We probably are. :) I'm using Workbench Moderation for a university client, but needed something more role-based than Workbench Access (or Content Access or Taxonomy Access, etc.) to meet their privilege model, so I wrote Conditional Roles. The Conditional Roles for Workbench Moderation module you found is just a bridge module between CR and WM; most of its code becomes unnecessary once this hook goes in.

If you'll be around, I'll catch up with you on #drupal-workbench on Monday.

robloach’s picture

muriqui’s picture

Status: Needs review » Needs work

Per a note from rfay, the patch was manually removed from the testing queue. He requested that the patch be moved to "needs work" and back to "needs review" to trigger the test, rather than using the retest link. So, moving to "needs work"...

muriqui’s picture

Status: Needs work » Needs review

... and back to "needs review."

muriqui’s picture

Re-rolled for current 7.x-1.x.

jthorson’s picture

Status: Needs review » Active

We're still having problems with the deployment of project_dependency on the testing infrastructure, and I suspect that workbench's dependency on views may have played a part in our most recent testing lock-up.

As a result, I'd like to try leaving this issue out of 'needs review' state until we get the project_dependency and pift patches deployed on d.o. (hopefully within a couple days) ... apologies in advance for the hassle, and thanks for your understanding.

jthorson’s picture

Status: Active » Needs review
StatusFileSize
new5.27 KB

Fingers crossed!

muriqui’s picture

@stevector, just wondering if there's been any movement on getting this committed since we discussed it back in October. Thanks!

Ale.bcn’s picture

sorry to bother but... I'm wondering too :)

ericduran’s picture

ericduran’s picture

Status: Needs review » Needs work
+++ b/workbench_moderation.moduleundefined
@@ -1326,14 +1326,18 @@ function workbench_moderation_transition_delete($transition) {
+  global $user;

This addition of the global $user doesn't make sense to me.

I didn't look at the code just the patch. I don't see any use of the global $user object in the patch so I'm confused why it's been added here.

Besides that I really like this patch. I think it'll be a good addition it'll also help me solve some issues I'm running into.

ericduran’s picture

+++ b/workbench_moderation.moduleundefined
@@ -1326,14 +1326,18 @@ function workbench_moderation_transition_delete($transition) {
+  $node_type = is_string($node) ? $node : $node->type;

I would also say lets get rid of this line. Lets just change it to $node_type = $node->type;

The one place left in the code that doesn't pass the $node object is in the workbench_moderation_form_node_form_alter function and that can easily be changes to pass in $form['#node'] instead of $form['type']['#value'].

The reason for this is that passing in the type will make us have to also use the same code in the alter hook and constantly check if we're getting the $node object of just a string. To prevent us from assuming the node is always being passed. Instead we should just fix all the places the node object isn't being passed in.

Anyone disagrees?

muriqui’s picture

@ericduran, to answer your questions...

This addition of the global $user doesn't make sense to me.

It's there because, at the time that I wrote the patch, that function did this a few lines later:

if (!$account) {
  $account = $user;
}

... Which, obviously, wouldn't work as intended without a global $user beforehand. However, since then, that segment has been changed to this:

if (empty($account)) {
  $account = $GLOBALS['user'];
}

... Which fixes it a different way. So, yes, we can eliminate the global $user from the patch now.

I would also say lets get rid of this line. Lets just change it to $node_type = $node->type;

The one place left in the code that doesn't pass the $node object is in the workbench_moderation_form_node_form_alter function and that can easily be changes to pass in $form['#node'] instead of $form['type']['#value'].

Well, if we're going to do that, why keep $node_type at all? Let's just change all instances of $node_type in the function to $node->type. Also, if we're changing workbench_moderation_form_node_form_alter() to pass the node object, then we should probably use $form_state['node'] instead of $form['#node'], given that the latter is slated to be removed, per this segment in node_form():

// @todo D8: Remove. Modules should access the node using $form_state['node'].
$form['#node'] = $node;
rv0’s picture

$node_type = is_string($node) ? $node : $node->type;

I've seen this pattern in node_access_hooks in other modules, and indeed, sometimes it is a string.
Don't know why drupal does this.

So before changing it, better make sure it wont break things.

muriqui’s picture

That's true with node_access hooks, but not here. The new hook in the patch is only ever invoked from within workbench_moderation_states_next(), and that function is only called a few different places within the module. If we're following ericduran's suggestion and ensuring that all of those calls are passing a node object, then there's no need to accept a string in workbench_moderation_states_next(). Currently, the only place that doesn't is the node_form alter hook, which receives a usable node object from node_form() in $form_state['node'], so if we pass that object instead, that should eliminate the need to test for a string.

ericduran’s picture

Status: Needs work » Needs review
StatusFileSize
new8.51 KB

Here's an updated patch with the above comments.

ericduran’s picture

StatusFileSize
new8.38 KB

Here's an updated patch with the api example updated.

I really like this patch because for now it lets me at least fake different states for different node types :).

stevector’s picture

Thanks for working on these issues Eric. I'm sorry I've been slow to get them reviewed. I should be able to get to this one next week. Just reading through it, it looks good.

tlaurent’s picture

I worked on a module to integrate Workbench Moderation with OG (so that the change of state permissions can be set for OG roles), and in the process had to be able to hook into how WM check the permissions for the change of states.
I went a (very slightly) different way, adding the hook into workbench_moderation_state_allowed rather than workbench_moderation_states_next.
I realised it'd silly to have several patches to solve the same problem and would like your opinions on the advantages/drawbacks of the different approaches (to know if it'd be better to change my code to use the previously submitted patches rather than mine).

avinoam’s picture

I used the last patch and it work well,

I think adding hooks to alter state_allowed is more successful from add hooks to states_next , becouse states_next relies on state_allowed.

just one comment to the patch: I think that the entire node object should pass to the state_allowed function and it's alter hooks, not just the id.

stevector’s picture

The patch in 31 works well for me. Thanks Eric! And thanks again to muriqui for starting this issue.

Thomas, I understand that altering on _allowed() also works. However I don't see an advantage to it since it is only called from _next(). So for me it boils down to one drupal_alter() call versus "n" calls with the _allowed() approach.

If there's not a strong argument to alter on _allowed(), I'll commit the _next() version.

That's independent of the node type vs. full object question that avinoam mentions. I agree that the full object is necessary.

Thanks for the hard work everyone.

muriqui’s picture

StatusFileSize
new8.02 KB

Fixing a bug in #31... In workbench_moderation_get_moderation_links(), it changes
if (!workbench_moderation_node_type_moderated($node->type)) {
to
if (!workbench_moderation_node_type_moderated($node)) {
which it shouldn't do, because workbench_moderation_node_type_moderated() expects a string value, so passing the full object breaks it. And _node_type_moderated() never calls _states_next(), so it doesn't need to be changed to accept the full object.

The attached patch removes that bug, but is otherwise the same as #31, which looks good to me. Can I get an RTBC?

Also, regarding the _next() vs. _allowed() issue, I agree with Steve that _next() is the right place for the alter hook. _allowed() is essentially just a permissions check on the user; no need to clutter it with node-based logic. In other words, the _allowed() loop in _next() yields the list of all transitions the user is allowed to make based solely on their permissions; once we have that, the alter hook can prune the list based on conditions on the node. Better to do it there in one swoop than to iteratively call alter hook implementations for each individual transition.

Status: Needs review » Needs work

The last submitted patch, 1108502-36-workbench_moderation.patch, failed testing.

stevector’s picture

This broke because I just committed a Rules patch which also modified the API page. I'll post a revised patch shortly.

stevector’s picture

Status: Needs work » Needs review
StatusFileSize
new8.07 KB

This should pass tests. I'll then RTBC and commit.

stevector’s picture

Status: Needs review » Reviewed & tested by the community

Commit coming momentarily.

stevector’s picture

Status: Reviewed & tested by the community » Fixed

Thanks muriqui, Eric and everyone who helped and tested this.

http://drupalcode.org/project/workbench_moderation.git/commit/b04fbf7ccf...

Status: Fixed » Closed (fixed)

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