You are here

function oa_user_access_nids in Open Atrium Core 7.2

Determine whether a user has a given privilege for groups.

This modules the logic of og_user_access but for multiple node groups. IMPORTANT, any changes to og_user_access reflect here.

We cannot offer any speed improvements if og_user_access_alter is implemented as it requires a entity_load.

Parameters

$group_type: This will fall through to og_user_access access if not 'node'

$nids: Array of node nids that are groups.

$string: String can be a string or array of strings (which diverges from og_user_access) of permissions to check. If an array is passed, it'll be TRUE for that group if user has ANY of the permissions.

Return value

An array of nids to access.

4 calls to oa_user_access_nids()
oa_og_subgroups_check_access in includes/oa_core.util.inc
Check access for this group's parents.
oa_user_access in includes/oa_core.util.inc
Replacement for og_user_access.
OgSubspacesSelectionHandler::buildEntityFieldQuery in plugins/entityreference/selection/OgSubspacesSelectionHandler.class.php
Build an EntityFieldQuery to get referencable entities.
OgSubspacesSelectionHandler::getGidsForCreate in plugins/entityreference/selection/OgSubspacesSelectionHandler.class.php
Get group IDs from URL or OG-context, with access to create group-content.
1 string reference to 'oa_user_access_nids'
oa_corePermissionWeb::test_oa_sectionsAccess in tests/oa_corePermissionWeb.test

File

includes/oa_core.util.inc, line 1555
Code for Utility functions for OpenAtrium spaces

Code

function oa_user_access_nids($group_type, $nids, $string, $account = NULL, $skip_alter = FALSE, $ignore_admin = FALSE) {
  global $user;
  $strings = is_array($string) ? $string : array(
    $string,
  );
  $access =& drupal_static(__FUNCTION__, array());
  if (empty($account)) {
    $account = $user;
  }
  $nids = drupal_map_assoc($nids);

  // Administer group permission. We don't cache it cause ignore_admin can change.
  if ($account->uid == 1 || !$ignore_admin && user_access('administer group', $account)) {
    $return = array();
    foreach ($nids as $nid) {
      $return[$nid] = TRUE;
    }
    return $return;
  }

  // We don't handle not-nodes (cause hard to look up owner), the alter hook
  // (it needs full node_load).
  $alter = module_implements('og_user_access_alter');
  foreach (array(
    'og_subgroups',
    'og_ui',
  ) as $remove) {
    $pos = array_search($remove, $alter);
    if ($pos !== FALSE) {
      unset($alter[$pos]);
    }
  }

  // We cannot replicate unknown alters or unsubscribe logic, so fallback.
  // @see og_ui_og_user_access_alter().
  if ($group_type != 'node' || !$skip_alter && $alter || in_array('unsubscribe', $strings)) {
    foreach ($nids as $nid) {
      foreach ($strings as $string) {
        if (!isset($access[$account->uid][$string][$nid])) {
          $access[$account->uid][$string][$nid] = og_user_access($group_type, $nid, $string, $account, $skip_alter, $ignore_admin);
        }
      }
    }
  }
  $lookup = array();
  $all_lookup = array();

  // Find what nodes/permissions still need to be looked up.
  foreach ($strings as $string) {
    if (!empty($access[$account->uid][$string])) {
      $lookup[$string] = array_diff_key($nids, $access[$account->uid][$string]);
    }
    else {
      $lookup[$string] = $nids;
    }
    if (!$lookup[$string]) {
      unset($lookup[$string]);
    }
  }
  foreach ($lookup as $string => $nids_array) {
    $all_lookup += $nids_array;
  }

  // Group manager has all privileges (if variable is TRUE).
  if ($all_lookup && !empty($account->uid) && variable_get('og_group_manager_full_access', TRUE)) {
    $authored = db_query('SELECT nid FROM {node} WHERE nid in (:nids) AND uid = :uid', array(
      ':nids' => $all_lookup,
      ':uid' => $account->uid,
    ))
      ->fetchCol();
    foreach ($authored as $nid) {
      foreach ($strings as $string) {
        $access[$account->uid][$string][$nid] = TRUE;
        unset($lookup[$string][$nid]);
        unset($all_lookup[$nid]);
      }
    }
  }
  if ($all_lookup && !empty($account->uid)) {

    // Add administer group as first permission checked (as most likely).
    if (!$ignore_admin) {
      array_unshift($strings, 'administer group');
    }

    /**
     * The query needed is quite complex for regular oa access.
     *
     * The rid in og_users_roles can either be associated with no group if
     * the roles have not been overriden or with the group if they have.
     *
     * The rid can either be associated with the user or the 'member' role
     * which is added automatically.
     *
     * Below is a sample query.
     * @code
     * SELECT om.gid, orp.permission
     * FROM og_role_permission orp
     * INNER JOIN og_role oro ON oro.rid = orp.rid
     * INNER JOIN og_membership om ON om.group_type = 'node' AND oro.group_type = 'node' AND om.entity_type='user'
     * INNER JOIN node n ON n.nid = om.gid
     * INNER JOIN field_data_og_roles_permissions fdp on fdp.entity_type = 'node' AND fdp.entity_id = om.gid
     * LEFT JOIN og_users_roles our ON our.rid = oro.rid AND our.uid = om.etid AND our.group_type = "node" AND our.gid = om.gid
     * WHERE om.etid = 159
     *   AND (oro.gid = om.gid OR (fdp.og_roles_permissions_value = 0 and oro.gid = 0 AND oro.group_bundle = n.type))
     *   AND (our.uid = 159 OR oro.name = 'member')
     *   AND om.state = 1 AND om.gid IN (139);
     * @endcode
     *
     * @todo BUNDLE DAMMIT
     */
    $query = db_select('og_role_permission', 'orp');
    $query
      ->innerJoin('og_role', 'oro', 'oro.rid = orp.rid');
    $query
      ->innerJoin('og_membership', 'om', "om.group_type = 'node' AND oro.group_type = 'node' AND om.entity_type='user'");
    $query
      ->innerJoin('node', 'n', "n.nid = om.gid");
    $query
      ->innerJoin('field_data_og_roles_permissions', 'fdp', "fdp.entity_type = 'node' AND fdp.entity_id = om.gid");
    $query
      ->leftJoin('og_users_roles', 'our', "our.rid = oro.rid AND our.uid = om.etid AND our.group_type = 'node' AND our.gid = om.gid");
    $query
      ->fields('om', array(
      'gid',
    ));
    $query
      ->fields('orp', array(
      'permission',
    ));
    $query
      ->condition('om.etid', $account->uid);
    $and = db_and()
      ->condition('fdp.og_roles_permissions_value', 0)
      ->condition('oro.gid', 0)
      ->where('n.type = oro.group_bundle');
    $or = db_or()
      ->where('oro.gid = om.gid')
      ->condition($and);
    $query
      ->condition($or);
    $or = db_or()
      ->condition('our.uid', $account->uid)
      ->condition('oro.name', 'member');
    $query
      ->condition($or);
    $query
      ->condition('orp.permission', $strings);
    $query
      ->condition('state', OG_STATE_ACTIVE);
    $query
      ->condition('om.gid', $all_lookup);
    $result = $query
      ->execute();
    $rows = $result
      ->fetchAll();
    foreach ($rows as $row) {
      $access[$account->uid][$row->permission][$row->gid] = TRUE;
      unset($lookup[$row->permission][$row->gid]);
    }
  }

  // Check parent access.
  // This needs further optomization.
  if ($lookup && !$skip_alter && in_array('og_subgroups', module_implements('og_user_access_alter'))) {
    $user_groups = og_subgroup_user_groups_load($account, FALSE);
    foreach ($lookup as $string => $nids_array) {
      foreach ($nids_array as $nid) {
        if (oa_og_subgroups_check_access($string, $group_type, $nid, $user_groups, TRUE)) {
          $access[$account->uid][$string][$nid] = TRUE;
          unset($lookup[$string][$nid]);
        }
      }
    }
  }

  // Any extra NID is no access.
  foreach ($lookup as $string => $nids_array) {
    foreach ($nids_array as $nid) {

      // This should not be set, but just in case only set to false if not.
      if (!isset($access[$account->uid][$string][$nid])) {
        $access[$account->uid][$string][$nid] = FALSE;
      }
    }
  }

  // Figure out if user has any access.
  $return = array();
  $remaining_nids = $nids;
  do {
    $string = array_shift($strings);
    if (!empty($access[$account->uid][$string])) {
      $return += array_filter(array_intersect_key($access[$account->uid][$string], $remaining_nids));
    }
    $remaining_nids = array_diff_key($nids, $return);
  } while ($remaining_nids && $strings);

  // If no strings left, there are no access.
  if ($remaining_nids) {
    foreach ($remaining_nids as $nid) {
      $return[$nid] = FALSE;
    }
  }

  // Need to return array as combination of strings.
  return $return;
}