When a node is *created*, we can define the resultant workflow. It would also be very useful to be able to define a workflow to result from when a node is *edited*.

In my site, I have a complex approval system for new content of a certain type which works really well, except that a user can edit a node once it has been "approved" and add content that would never have been "approved".

Comments

jeff h’s picture

My project is really going to need this... is anyone interested in coding it for me (let me know how many $$)?

MrTaco’s picture

the node_perm module and atleast one other, already purport to be able to change the editability of a node (for a given role) when certain workflow state transitions occur on that node

personally, i have tried node_perm and it did not work (i think it conflicted with another permissions module i use), but i think you should give them a try

RobRoy’s picture

Title: node edit state » Make transition from Current State to Current State optional (and force a transition away from current state on node edit)
Version: 6.x-1.x-dev » 4.7.x-1.x-dev
Status: Active » Needs review
StatusFileSize
new6.55 KB

This patch is for 4.7.x and includes some basic whitespace cleanup and a few comment changes next to code I modified. I can roll one for HEAD once I get some reviews on this.

Here is the use case Jeff H is talking about:

In our case, when a recipe is submitted, it is assigned a workflow state of "pending review". Then, once a recipe is approved, the user will still be allowed to edit it, but doing so won't set the state back to "pending review". This has fairly concerning implications regarding dodgy content appearing like it was approved.

So we need to be able to FORCE a node to a workflow state just like we force (creation) -> the next available state. This patch covers that.

NOTE: You now must explicitly give an author/role X permission to go from State X -> State X. If a node is in State X and the only allowed transition for that user is State X -> State Y, upon saving the node it will trigger a workflow transition from X to Y. So if you want to do something like Jeff H does above, don't allow X -> X for a specific role, only allow X -> Y in the edit workflow transition grid.

We might want to include an workflow_update_5() to auto-check the author boxes for all State X -> State X transitions for people who are upgrading. Thoughts?

John, you've built a kick ass module! This definitely needs some testing as since maybe I'm missing something. :)

RobRoy’s picture

bdragon’s picture

Version: 4.7.x-1.x-dev » 5.x-1.1
StatusFileSize
new3.98 KB

I rolled back the whitespace changes to reduce conflicts and updated the patch to DRUPAL-5.

Hopefully I didn't miss anything.

udvranto’s picture

This does not work. I tried commenting return in function workflow_execute_transition as shown in the code. But this causes stack overflow. Any solution?

[code]
function workflow_execute_transition($node, $sid, $comment = NULL) {
$old_sid = workflow_node_current_state($node);
if ($old_sid == $sid) { // stop if not going to a different state
// Write comment into history though.
if ($comment && !$node->_workflow_scheduled_comment) {
$node->workflow_stamp = time();
db_query("UPDATE {workflow_node} SET stamp = %d WHERE nid = %d", $node->workflow_stamp, $node->nid);
_workflow_write_history($node, $sid, $comment);
}
// we dont want to skip same stats
// return;
}

[/code]

udvranto’s picture

Version: 5.x-1.1 » 4.7.x-1.x-dev

I tried to apply this patch for same state to same state workflow transition. The actions do not get applied during same state transitions! I tried commenting return statement in the function workflow_execute_transition as shown below. This causes the actions for same state transition to be applied but also causes stack overflow on new posts.

I tried the other patch. But this is the one I want as a solution for my problem.

function workflow_execute_transition($node, $sid, $comment = NULL) {
  $old_sid = workflow_node_current_state($node);
  if ($old_sid == $sid) { // stop if not going to a different state
    // Write comment into history though.
    if ($comment && !$node->_workflow_scheduled_comment) {
      $node->workflow_stamp = time();
      db_query("UPDATE {workflow_node} SET stamp = %d WHERE nid = %d", $node->workflow_stamp, $node->nid);
      _workflow_write_history($node, $sid, $comment);
    }
    // return;
  }
udvranto’s picture

When a new node is created workflow_nodeapi is called with $op=="insert". After this actions get applied which in turns calls node_save and workflow_nodeapi with $op=="update". A recursive loop is avoided with a check on transition state. This is same for node edit as well.

If I do the following in workflow.module function workflow_nodeapi

        // check to see if this is an immediate change or a scheduled change
        if (!$node->workflow_scheduled) {
          if( ($op == 'insert' && $sid != workflow_node_current_state($node)) ||
            $op == 'update' )
            workflow_execute_transition($node, $sid, $node->workflow_comment); // do transition
        }
        else { // schedule the the time to change the state

and comment the following code in function workflow_execute_transition

/*
  if ($old_sid == $sid) { // stop if not going to a different state
    // Write comment into history though.
    if ($comment && !$node->_workflow_scheduled_comment) {
      $node->workflow_stamp = time();
      db_query("UPDATE {workflow_node} SET stamp = %d WHERE nid = %d", $node->workflow_stamp, $node->nid);
      _workflow_write_history($node, $sid, $comment);
    }
    return;
  }
*/

then no transition check is used and new node creation falls into a recursive loop causing a stack overflow. But the edit works somehow. Now the problem is how to avoid the recursive callback?

udvranto’s picture

This is what I am doing now in workflow_nodeapi function

    case 'insert':
      global $workflow_insert_initiated;
      $workflow_insert_initiated = true;
    case 'update':
      global $workflow_insert_initiated;
      if($op=='update' && $workflow_insert_initiated==true) {
        $workflow_insert_initiated = false;
        break;
      }

      // stop if no workflow for this node type
      $wid = workflow_get_workflow_for_type($node->type);
      if (!$wid) {
        break;
      }

In function workflow_execute_transition

/*  if ($old_sid == $sid) { // stop if not going to a different state
    // Write comment into history though.
    if ($comment && !$node->_workflow_scheduled_comment) {
      $node->workflow_stamp = time();
      db_query("UPDATE {workflow_node} SET stamp = %d WHERE nid = %d", $node->workflow_stamp, $node->nid);
      _workflow_write_history($node, $sid, $comment);
    }
    return;
  }*/

Now I am getting "This content has been modified by another user, changes cannot be saved." Any idea?

udvranto’s picture

I believe I have a solution now. Along with the patch submitted by RobRoy in comment 3, you will need to replace the following function

/**
 * Execute a transition (change state of a node).
 * Updated by S M Mahbub Murshed July 13, 2007
 * to support same state change  
 *
 * @param object $node
 * @param int $sid
 * @return int ID of new state.
 */
function workflow_execute_transition($node, $sid, $comment = NULL) {
  global $workflow_execute_transition_initiated;
  if($workflow_execute_transition_initiated) {    
    return;
  }

  $workflow_execute_transition_initiated = true;
  $old_sid = workflow_node_current_state($node);

  // Make sure this transition is valid and allowed for the current user.
  global $user;
  if ($user->uid > 1) { // allow any state change for superuser (might be cron)
    $tid = workflow_get_transition_id($old_sid, $sid);
    if (!$tid) {
      watchdog('workflow', t('Attempt to go to nonexistent transition (from %old to %new)', array('%old' => $old_sid, '%new' => $sid), WATCHDOG_ERROR));
      $workflow_execute_transition_initiated = false;
      return;
    }
    if (!workflow_transition_allowed($tid, array_merge(array_keys($user->roles), array('author')))) {
      watchdog('workflow', t('User %user not allowed to go from state %old to %new)', array('%user' => $user->name, '%old' => $old_sid, '%new' => $sid), WATCHDOG_NOTICE));
      $workflow_execute_transition_initiated = false;
      return;
    }
  }

  // Invoke a callback indicating a transition is about to occur. Modules
  // may veto the transition by returning FALSE.
  $result = module_invoke_all('workflow', 'transition pre', $old_sid, $sid, $node);

  if (in_array(FALSE, $result)) { // stop if a module says so
    $workflow_execute_transition_initiated = false;
    return;
  }
  
  _workflow_node_to_state($node, $sid, $comment); // change the state

  // Register state change with watchdog
  $state_name = db_result(db_query("SELECT state FROM {workflow_states} WHERE sid = %d", $sid));
  $type = check_plain(node_get_name($node->type)); //module_invoke($node->type, 'node_name', $node);
  $state_name = check_plain($state_name);
  watchdog('workflow', t('State of %type %node_title set to %state_name', array('%type' => $type, '%node_title' => theme('placeholder', $node->title), '%state_name' => $state_name)), WATCHDOG_NOTICE, l('view', $node->nid));

  // Notify modules that transition has occurred. Actions should take place
  // in response to this callback, not the previous one.
  module_invoke_all('workflow', 'transition post', $old_sid, $sid, $node);
  
  // clear any references in the scheduled listing
  db_query('DELETE FROM {workflow_scheduled_transition} WHERE nid = %d', $node->nid);
  $workflow_execute_transition_initiated = false;
}
udvranto’s picture

I forgot to describe the problem I was having. I was trying to solve the problem I described here. I needed actions in same-same transitions. Thats what I tried to do here. IMO, having same state transitions give more flexibility and should be added into the core.

gemini’s picture

Version: 4.7.x-1.x-dev » 5.x-1.1

I applied the patch replace the function, but then I got "This content has been modified by another user, changes cannot be saved." And now the workflow block does not appear of the user in the node edit. Any ideas?

gemini’s picture

Ok, I tried it again and the patch in the message 3 by RobRoy worked. I guess I overwritten the wrong function. Thanks!

kirby’s picture

Sorry, but I don't get the whole discussion.

So is it possible to make transition from Current State to Current State optional with Drupal 5.5 ?
Which patch should I use and are there any modification I have to make by myself (in file workflow.module or in the database) ?

Thank you

JacobSingh’s picture

Status: Needs review » Needs work

This doesn't look complete to me, and to be honest, I'm also a little confused as to what's going on.

Is the intention that:
We provide workflow state change access params so that the matrix allows you to specify which roles can transition between x and x, not just x and y?

For instance,
only editors can go from approved to approved, other users can only go from approved to "in moderation".

Is that the goal?

If so, whomever is working on this, can you specify what you are changing (from a front-end perspective) and provide a patch which can be applied to the DRUPAL-5 tag?

Best,
Jacob

bdragon’s picture

Yeah, that's the sort of thing I've been using my patch in #5 for.

bdragon’s picture

Version: 5.x-1.1 » 5.x-1.2
Status: Needs work » Needs review
StatusFileSize
new4.24 KB

Here's a patch against current DRUPAL-5.

The idea is to allow "forcing" content out of a state if the editor doesn't have permission to stay in the current state.

I know the patch itself seems a bit odd, but it's worked so far for me...

Thoughts?

ntt’s picture

subscribing

chansion.vc’s picture

How about D6 ?

Bastlynn’s picture

Status: Needs review » Closed (won't fix)

Hi,

With the release of Drupal 7, Drupal 5 is no longer receiving security updates, reviews, or development from many contributed modules. Since 5 is now considered a depreciated version, you really should seriously look into upgrading to Drupal 6 or 7. The newer versions of Drupal work better, have more support, and will be safer (literally! security patches!) for your website. We are currently working on a new release for Workflow to Drupal 7. In light of that, further support for Drupal 5 issues is infeasible at the moment. Please consider upgrading to Drupal 6 or 7 in the near future - you'll be glad you did.

- Bastlynn

greenskin’s picture

Version: 5.x-1.2 » 7.x-1.x-dev
Status: Closed (won't fix) » Active

How can I do this in the 7.x version?

nancydru’s picture

Status: Active » Closed (works as designed)

I would think you could set up a rule to fire on "After updating existing content." In the rule you can check if the node has any forbidden states and change the state.

The Workflow Access module (included) will disallow editing of nodes in certain states. I would think that stopping the problem before it happens would be a better solution.

greenskin’s picture

My issue is I want an author to still be able to edit a piece of content but not have approval to change states, an editor would do that. But I want when an author edits a node in the final state it to be moved back to a lower state. The "Set workflow state for content" rules action appears to still check if the user has permission to make the transition. I want to force the transition, not simply allow the author to move it back. Your thoughts? Thanks!

nancydru’s picture