an issue in role_watchdog to get their opinion about how to integrate with ubercart (uc_roles): #1142950: integrate with ubercart and uc_roles

Maybe ubercart can do something like #341162: Module should use user_save instead of directly accessing drupal database (drupal5 patch). Is there a reason not to?

CommentFileSizeAuthor
#2 uc_roles-user_save.patch1000 bytesjohn.money

Comments

yesct’s picture

hmmm. uc_roles does seem to use user_save:

around line 1177 of uc_roles.module:

/**
 * Revoke a role on a given user
 *
 * @param $account
 *   A Drupal user object.
 * @param $rid
 *   A Drupal role ID.
 * @param $silent
 *   When set to TRUE will suppress any Drupal messages from this function.
 *
 * This function deletes a given role from a user's list of roles, as
 * well as removing any expiration data associated with the user/role.
 * The function notifies the user of revocation.
 */
function uc_roles_revoke($account, $rid, $silent = FALSE) {
  global $user;

  // Remove this role from the user's list.
  $roles_list = &$account->roles;
  unset($roles_list[$rid]);

  user_save($account, array('roles' => $roles_list));

  // Remove our record of the expiration.
  uc_roles_delete($account, $rid);

  $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));

  if (!$silent) {
    if ($user->uid == $account->uid) {
      drupal_set_message(t('Your %role role has been revoked.', array('%role' => $role_name)));
    }
    else {
      drupal_set_message(t('%user has had the %role role revoked.', array('%user' => $account->name, '%role' => $role_name)));
    }
  }
}

and around 1224

/**
 * Grant a role to a given user *
 * @param $account
 *   A Drupal user object.
 * @param $rid
 *   A Drupal role ID.
 * @param $timestamp
 *   When this role will expire.
 * @param $save_user
 *   Optimization to prevent unnecessary user saving when calling from hook_user(
).
 * @param $silent
 *   When set to TRUE will suppress any Drupal messages from this function.
 *
 * This function grants a given role to a user's list of roles. If there
 * is a previous record of this user/role combination, it is first removed. * The function then saves the user (if $user_save is TRUE). Next, a check
 * to verify the role actually exists, if not, no expiration data is stored.
 * The menu cache is flushed, as new menu items may be visible after the
 * new role is granted. The function notifies the user of the role grant.
 */

function uc_roles_grant(&$account, $rid, $timestamp, $save_user = TRUE, $silent = FALSE) {
  global $user;

  // First, delete any previous record of this user/role association.
  uc_roles_delete($account, $rid, $silent);

  if ($save_user) {
    // Punch the role into the user object.
    $account->roles += array($rid => _uc_roles_get_name($rid));
    user_save($account, array('roles' => $account->roles));
  }

  // If the role expires, keep a record.
  if (!is_null($timestamp)) {
    db_query("INSERT INTO {uc_roles_expirations} (uid, rid, expiration) VALUES (%d, %d, %d)", $account->uid, $rid, $timestamp);
  }

  // Flush visible menu items, since our permissions could've changed.
  _uc_roles_flush_menu_cache($account);

  // Display the message if appropriate.
  if (!$silent) {
    $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));

    if ($user->uid == $account->uid) {
      $message = t('You have been granted the %role role.', array('%role' => $role_name));
    }
    else {
      $message = t('%user has been granted the %role role.', array('%user' => $account->name, '%role' => $role_name));
    }

    if ($timestamp) {
      $message .= t(' It will expire on %date', array('%date' => format_date($timestamp, 'small')));
    }

    drupal_set_message($message);
  }
}
john.money’s picture

Title: Integrate with role_watchdog (modify uc_roles to use user_save) by using user_save instead of modifying the database directly » $account object modified before user_save() prevents detecting role changes
Status: Active » Needs review
StatusFileSize
new1000 bytes

uc_roles_revoke() and uc_roles_grant() both modify the $account object before user_save() is done. So when another module attempts to identify any role changes, it cannot detect any since $account already reflects the new role state. This is not necessary, since user_save will return a fully-built $user object.

Here is example:

At line 1174 of uc_roles.module in function uc_roles_revoke()

  $roles_list = &$account->roles;

If however, I change that line to:

  $roles_list = $account->roles;

...we are able to compare the previous $account with the new $edit values.

Attached is a patch to uc_roles which should (very light testing) preserve all uc_roles behavior while still letting user_save do its thing.

yesct’s picture

Status: Needs review » Reviewed & tested by the community

I tested it, and it lets roles added by uc be tracked.

longwave’s picture

Version: 6.x-2.x-dev » 7.x-3.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed to 6.x, thanks for the patch.

longwave’s picture

This applies cleanly to 7.x but not sure if it's needed, as D7 core user_save() looks like it provides $account->original to compare against in hooks.

longwave’s picture

Status: Patch (to be ported) » Postponed
longwave’s picture

Version: 7.x-3.x-dev » 6.x-2.x-dev
Status: Postponed » Fixed

Committed to 7.x anyway to minimise changes between versions.

Status: Fixed » Closed (fixed)

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

yesct’s picture

my code for ubercart is updated, and I manually checked that the changes from that patch were included, and they are, but. expiring roles granted via uc_roles feature are not logged in the Roles tab (via roles watchdog). Maybe something else with uc or role watchdog has changed.

yesct’s picture

I have: 6.x-1.2 role watchdog and 6.x-2.7 ubercart roles