You are here

oa_core.access.inc in Open Atrium Core 7.2

Code for Access Control functions for OpenAtrium spaces

File

includes/oa_core.access.inc
View source
<?php

/**
 * @file
 * Code for Access Control functions for OpenAtrium spaces
 */

/**
 * Determine access to a Open Atrium Section
 * do NOT use node_load here as it gets called from hook_node_grants()
 * TODO: No longer called from node_grants, but called from tests.  Is this still needed?
 */
function oa_core_section_access($row, $spaces, $account) {
  $gid = $row['field_oa_group_ref_target_id'];
  $team_id = $row['field_oa_team_ref_target_id'];
  $user_id = $row['field_oa_user_ref_target_id'];

  // check if no access fields are set
  if (is_null($gid) && is_null($team_id) && is_null($user_id)) {
    return NODE_ACCESS_ALLOW;
  }

  // Test Group membership
  if (!is_null($gid) && !empty($spaces['node'])) {
    if (in_array($gid, $spaces['node'])) {
      return NODE_ACCESS_ALLOW;
    }
  }

  // Test Team membership
  if (!is_null($team_id)) {
    if (oa_core_member_of_team($team_id, $account->uid)) {
      return NODE_ACCESS_ALLOW;
    }
  }

  // Test User membership
  if (!is_null($user_id)) {
    if ($user_id == $account->uid) {
      return NODE_ACCESS_ALLOW;
    }
  }

  // none of the groups, teams, or users allowed access, so deny access
  return NODE_ACCESS_DENY;
}

/**
 * Implements hook_og_subgroups_is_parent_private_alter().
 * Handle special Atrium case where a private Group Parent does not make a public
 * space private.  Only having a private SPACE Parent makes a public space private.
 * @param $result
 * @param $entity_type
 * @param $entity
 */
function oa_core_og_subgroups_is_parent_private_alter(&$result, $entity_type, $entity) {
  if ($result && $entity_type == 'node') {
    if ($entity->type == OA_GROUP_TYPE) {

      // A Private parent GROUP does not make the child space private
      $result = FALSE;
    }
  }
}

/**
 * Implements hook_node_grants().
 * Define node access grant realm for Open Atrium sections
 */
function oa_core_node_grants($account, $op) {
  $cache =& drupal_static('oa_core_node_grants', array());
  if ($op != 'view' || !$account->uid) {
    return array();
  }
  if (isset($cache[$account->uid])) {
    return $cache[$account->uid];
  }

  // Handle unpublished content permissions
  if (user_access('view own unpublished content') && $account->uid) {
    $grants[OA_UNPUBLISHED_REALM] = array(
      $account->uid,
    );
  }

  // Combine the spaces the user is part of with public spaces.
  $member_spaces = oa_core_get_groups_by_user($account, 'node');
  $spaces = array_merge($member_spaces, oa_core_get_public_spaces(array(
    OA_SPACE_TYPE => OA_SPACE_TYPE,
  ), NULL, FALSE, FALSE));
  if (!empty($spaces)) {
    $query = db_select('node', 'n');

    // Join the og table to filter by spaces.
    $query
      ->join('og_membership', 'og', "n.nid = og.etid AND og.entity_type = 'node' AND og.field_name = '" . OA_SPACE_FIELD . "'");
    $query
      ->condition('og.gid', $spaces, 'IN');

    // we join with the Groups, Teams, Users fields
    $query
      ->fields('n', array(
      'nid',
    ));
    $query
      ->condition('n.type', OA_SECTION_TYPE);

    // Create an or condition that finds if section is allowed.
    $db_or = db_or();

    // Allow author of section.
    $db_or
      ->condition('n.uid', $account->uid, '=');

    // If user is specified in user ref column.
    $query
      ->leftJoin('field_data_field_oa_user_ref', 'u', "n.nid = u.entity_id AND u.entity_type = 'node'");
    $db_or
      ->condition('u.field_oa_user_ref_target_id', $account->uid, '=');

    // If one of the groups are included.
    if ($member_spaces) {
      $query
        ->leftJoin('field_data_field_oa_group_ref', 'o', "n.nid = o.entity_id AND o.entity_type = 'node'");
      $db_or
        ->condition('o.field_oa_group_ref_target_id', $member_spaces, 'IN');
    }

    // If one of the teams are included.
    $query
      ->leftJoin('field_data_field_oa_team_ref', 't', "n.nid = t.entity_id AND t.entity_type = 'node'");
    $query
      ->leftJoin('node', 'tn', "tn.nid = t.field_oa_team_ref_target_id");

    // Add creater of team.
    $db_or
      ->condition('tn.uid', $account->uid, '=');
    $query
      ->leftJoin('field_data_field_oa_team_users', 'tu', "t.field_oa_team_ref_target_id = tu.entity_id AND tu.entity_type = 'node' AND tu.deleted=0");

    // If user is part of team.
    $db_or
      ->condition('tu.field_oa_team_users_target_id', $account->uid, '=');

    // Add or to query.
    $query
      ->condition($db_or);

    // Set grants to nids, which should be only valid ones.
    $grants[OA_ACCESS_REALM] = $query
      ->execute()
      ->fetchCol(0);
  }
  $cache[$account->uid] = !empty($grants) ? $grants : array();
  return $cache[$account->uid];
}

/**
 * Implements hook_node_access_records().
 */
function oa_core_node_access_records($node) {
  $grants = array();
  $sids = array();
  if ($node->status == 0) {

    // Grant author access to unpublished content.
    if ($node->uid) {
      $grants[] = array(
        'realm' => OA_UNPUBLISHED_REALM,
        'gid' => $node->uid,
        'grant_view' => 1,
        'grant_update' => 0,
        'grant_delete' => 0,
        'priority' => 0,
      );
    }
    return $grants;
  }
  elseif ($node->type == OA_SECTION_TYPE) {
    if (!oa_core_section_is_public($node)) {
      $sids[] = $node->nid;
    }
  }
  elseif (!empty($node->{OA_SECTION_FIELD})) {
    foreach ($node->{OA_SECTION_FIELD}[LANGUAGE_NONE] as $entity_ref) {
      $section = node_load($entity_ref['target_id']);
      if (!oa_core_section_is_public($section)) {
        $sids[] = $entity_ref['target_id'];
      }
    }
  }
  if (empty($sids)) {
    return array();
  }
  foreach ($sids as $sid) {
    $grants[] = array(
      'realm' => OA_ACCESS_REALM,
      'gid' => $sid,
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
      // Priority 1 means lesser grants for this node will be ignored.
      'priority' => 1,
    );
  }
  return !empty($grants) ? $grants : array();
}

/**
 * Implements hook_node_access().
 *
 * Add proper 'create' access checks that OG doesn't handle
 */
function oa_core_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
  if ($op == 'create' && ($type == OA_SPACE_TYPE || og_is_group_content_type('node', $type))) {

    // In og.module, og_node_access doesn't handle 'create' because
    // it doesn't have a Group context.
    // Well, in OA2 we *have* a Group context most of the time.
    // Can't call oa_core_get_space_context() however since
    // og_context_determine_context() will cause an infinite loop
    if (defined('OG_SESSION_CONTEXT_ID') && isset($_SESSION[OG_SESSION_CONTEXT_ID])) {
      $space_id = $_SESSION[OG_SESSION_CONTEXT_ID];

      // so let's use that to test 'create' access
      if ($space_id) {
        $return = og_user_access('node', $space_id, "{$op} {$type} content", $account);
        if ($return) {
          return NODE_ACCESS_ALLOW;
        }
      }
      if ($type != OA_SPACE_TYPE) {
        return NODE_ACCESS_DENY;
      }
    }
  }
  return NODE_ACCESS_IGNORE;
}

/**
 * Implements hook_node_update().
 *
 * if saving a section or space node, update access locks on related content
 */
function oa_core_node_update($node) {
  if ($node->type == OA_SPACE_TYPE || $node->type == OA_GROUP_TYPE) {

    // check if group access changed and update space content grants
    $rebuild = module_invoke_all('oa_core_og_content_needs_rebuild', $node);
    if (in_array(TRUE, $rebuild, TRUE)) {

      // Get all subgroups for this node.
      $subgroup_nids = oa_core_get_groups_by_parent($node->nid, $node->type, NULL, FALSE, NULL, TRUE, FALSE);
      $batch = batch_get();

      // Don't do nested batch
      if (empty($batch)) {

        // Prepare the batch.
        _oa_core_update_access_records_batch_prepare($subgroup_nids);

        // Trigger the batch.
        batch_process();
      }
      else {
        oa_core_update_access_records($subgroup_nids);
      }
    }
    oa_core_clear_group_cache($node);
  }
  elseif ($node->type == OA_SECTION_TYPE) {

    // if section node changed from public to private, update content grants
    $was_public = oa_core_section_is_public($node->original);
    $is_public = oa_core_section_is_public($node);
    if ($was_public != $is_public) {

      // rebuild section content nodes
      $nids = db_select('field_data_' . OA_SECTION_FIELD, 'n')
        ->fields('n', array(
        'entity_id',
      ))
        ->condition('n.entity_type', 'node')
        ->condition('n.oa_section_ref_target_id', $node->nid)
        ->execute()
        ->fetchCol(0);

      // clear the static node cache for the space node so correct access
      // values are tested in hook_node_access_records
      entity_get_controller('node')
        ->resetCache(array(
        $node->nid,
      ));
      oa_core_update_access_records($nids);
    }
  }
}

/**
 * Update the node_access_records of the given nodes.
 *
 * @param array $nids
 *   Node nids that need updated node grants.
 */
function oa_core_update_access_records($nids) {
  drupal_static_reset('oa_core_node_grants');
  foreach ($nids as $nid) {
    $node = node_load($nid);

    // Clear the static node cache for the space node so correct access
    // values are tested in hook_node_access_records.
    entity_get_controller('node')
      ->resetCache(array(
      $nid,
    ));

    // Update the node grants.
    node_access_acquire_grants($node);
  }
}

/**
 * Set up the batch process to update node records.
 *
 * @param array $subgroup_nids
 *   Nids for all subgroups of the node being updated.
 */
function _oa_core_update_access_records_batch_prepare($subgroup_nids) {

  // Define the batch.
  $batch = array(
    'title' => t('Updating node access records due to a change in "Group Visibility"'),
    'init_message' => t('Preparing to update records.'),
    'operations' => array(
      array(
        '_oa_core_update_access_records_batch',
        array(
          $subgroup_nids,
        ),
      ),
    ),
    'finished' => '_oa_core_update_access_records_batch_finished',
  );

  // Set the batch using a helper in case drush is used.
  oa_core_batch_set($batch);
}

/**
 * Batch for updating node access records.
 *
 * @param array $subgroup_nids
 *   Nids for all subgroups of the node being updated.
 * @param array $context
 *   Carried over between batches.
 */
function _oa_core_update_access_records_batch($subgroup_nids, &$context) {
  if (empty($context['sandbox']['nids'])) {
    $context['sandbox']['nids'] = $subgroup_nids;

    // These are nids returned from oa_core_get_groups_by_parent().
    foreach ($subgroup_nids as $nid) {

      // Get membership nids using the og_group_ref field.
      $membership_nids = oa_core_get_membership_nodes($nid);

      // Merge the results.
      $new_array = array_merge($context['sandbox']['nids'], $membership_nids);

      // Update the sandbox.
      $context['sandbox']['nids'] = $new_array;
    }
    $context['results'] = count($context['sandbox']['nids']);
  }

  // Number of nodes updated per pass.
  $records_per_pass = 25;

  // Define the records to run for this pass.
  $current_records = array_splice($context['sandbox']['nids'], 0, $records_per_pass);

  // Update the node access records for this pass.
  oa_core_update_access_records($current_records);

  // We are done when the sandbox nids array is empty.
  $context['finished'] = empty($context['sandbox']['nids']) ? 1 : 0;
}

/**
 * Called when the batch is finished.
 *
 * @param boolean $success
 * @param int $results
 * @param $operations
 */
function _oa_core_update_access_records_batch_finished($success, $results, $operations) {
  if ($success && !empty($results)) {
    drupal_set_message(t('Updated node access records for @count nodes.', array(
      '@count' => $results,
    )));
  }
}

/**
 * Implements hook_oa_core_og_content_needs_rebuild().
 */
function oa_core_oa_core_og_content_needs_rebuild($node) {
  return isset($node->group_access[LANGUAGE_NONE][0]['value']) && isset($node->original->group_access[LANGUAGE_NONE][0]['value']) && $node->group_access[LANGUAGE_NONE][0]['value'] != $node->original->group_access[LANGUAGE_NONE][0]['value'];
}

/**
 * Implements hook_file_entity_access().
 *
 * Check permissions of private files based upon the node they are attached to
 */
function oa_core_file_entity_access($op, $file, $account) {
  if (is_object($file) && in_array($op, array(
    'view',
    'download',
  ))) {
    $scheme = file_uri_scheme($file->uri);
    $wrapper = file_entity_get_stream_wrapper($scheme);
    if (!empty($wrapper['private'])) {
      $query = db_select('node', 'n');
      if (user_access('view revisions')) {
        $query
          ->join('field_revision_field_oa_media', 'f', "n.nid = f.entity_id AND f.entity_type = 'node'");
      }
      else {
        $query
          ->join('field_data_field_oa_media', 'f', "n.nid = f.entity_id AND f.entity_type = 'node'");
      }
      $nids = $query
        ->fields('n', array(
        'nid',
      ))
        ->condition('f.field_oa_media_fid', $file->fid)
        ->addTag('node_access')
        ->execute()
        ->fetchCol(0);

      // add paragraph references
      if (module_exists('paragraphs')) {
        $query = db_select('node', 'n');
        if (user_access('view revisions')) {
          $query
            ->join('field_revision_field_oa_related', 'r', "n.nid = r.entity_id AND r.entity_type = 'node'");
          $query
            ->join('field_revision_field_oa_media', 'f', "r.field_oa_related_value = f.entity_id AND f.entity_type = 'paragraphs_item'");
        }
        else {
          $query
            ->join('field_data_field_oa_related', 'r', "n.nid = r.entity_id AND r.entity_type = 'node'");
          $query
            ->join('field_data_field_oa_media', 'f', "r.field_oa_related_value = f.entity_id AND f.entity_type = 'paragraphs_item'");
        }
        $related_nids = $query
          ->fields('n', array(
          'nid',
        ))
          ->condition('f.field_oa_media_fid', $file->fid)
          ->addTag('node_access')
          ->execute()
          ->fetchCol(0);
        $nids = array_merge($nids, $related_nids);
      }
      if (!empty($nids)) {
        $nids = array_unique($nids);

        // Ensure the user *really* has access to the nodes
        // since addTag('node_access') doesn't call node_access hooks.
        // Since the number of nodes the file is attached to is small, this
        // shouldn't be a performance issue.
        if (user_access('view files', $account)) {
          foreach ($nids as $nid) {
            if (($node = node_load($nid)) && node_access('view', $node, $account)) {
              return FILE_ENTITY_ACCESS_ALLOW;
            }
          }
        }

        // Otherwise, file is attached to nodes we don't have access to
        // so deny access.
        return FILE_ENTITY_ACCESS_DENY;
      }
      else {

        // File is not attached to a node we have specific node grants for
        // so now check if file is attached to ANY other revision.
        $query = db_select('node', 'n');
        $query
          ->join('field_revision_field_oa_media', 'f', "n.nid = f.entity_id AND f.entity_type = 'node'");
        $nids = $query
          ->fields('n', array(
          'nid',
        ))
          ->condition('f.field_oa_media_fid', $file->fid)
          ->execute()
          ->fetchCol(0);

        // add paragraph references
        if (module_exists('paragraphs')) {
          $query = db_select('node', 'n');
          $query
            ->join('field_data_field_oa_related', 'r', "n.nid = r.entity_id AND r.entity_type = 'node'");
          $query
            ->join('field_data_field_oa_media', 'f', "r.field_oa_related_value = f.entity_id AND f.entity_type = 'paragraphs_item'");
          $related_nids = $query
            ->fields('n', array(
            'nid',
          ))
            ->condition('f.field_oa_media_fid', $file->fid)
            ->execute()
            ->fetchCol(0);
          $nids = array_merge($nids, $related_nids);
        }
        if (empty($nids)) {

          // File is not referenced by any node revision, so allow it if they can access content
          // Open Atrium treats unattached files as public since everything is
          // stored in the private file system.
          if (user_access('access content', $account) && user_access('view files', $account) && !user_access('view private files', $account)) {

            // Default Open Atrium permissions are set, so allow access.
            return FILE_ENTITY_ACCESS_ALLOW;
          }
          else {
            return FILE_ENTITY_ACCESS_IGNORE;
          }
        }
        else {

          // File is referenced by node that we don't have access to, so deny.
          return FILE_ENTITY_ACCESS_DENY;
        }
      }
    }
  }
  return FILE_ENTITY_ACCESS_IGNORE;
}

/**
 * Implements hook_query_media_browser_alter().
 * Add private file access support to media browser
 */
function oa_core_query_media_browser_alter(QueryAlterableInterface $query) {
  if (!user_access('administer nodes') && module_implements('node_grants')) {

    // first, remove the existing condition from media.media.inc that prevents private files
    $where =& $query
      ->conditions();
    foreach ($where as $delta => $condition) {
      if (isset($condition['value']) && isset($condition['operator']) && $condition['value'] == 'private://%' && $condition['operator'] == 'NOT LIKE') {
        unset($where[$delta]);
        break;
      }
    }

    // next, add a proper node_access query restriction
    $or = db_or();

    // Ensure that the query is against the file_managed table.
    $tables = $query
      ->getTables();
    if (empty($tables['file_managed'])) {
      throw new Exception(t('Media browser being queried without the file_managed table.'));
    }
    $alias = $tables['file_managed']['alias'];

    // get down to which node has the attachment
    $query
      ->addJoin('LEFT', 'field_data_field_oa_media', 'media_field', "media_field.field_oa_media_fid = {$alias}.fid AND media_field.entity_type = 'node'");
    $query
      ->addJoin('LEFT', 'node', 'node', "node.nid = media_field.entity_id");
    $query
      ->addJoin('LEFT', 'node_access', 'node_access', "node.nid = node_access.nid");

    // this is from views_handler_filter_node_access.inc
    // cannot just use the addTag('node access') because base table of query is not node
    $table = 'node_access';
    $grants = db_or();
    foreach (node_access_grants('view') as $realm => $gids) {
      foreach ($gids as $gid) {
        $grants
          ->condition(db_and()
          ->condition($table . '.gid', $gid)
          ->condition($table . '.realm', $realm));
      }
    }
    $or
      ->condition(db_and()
      ->condition($grants)
      ->condition($table . '.grant_view', 1, '>='));

    // finally, put back the "private" condition as an OR state for public files
    $or
      ->condition($alias . '.uri', db_like('private://') . '%', 'NOT LIKE');
    $query
      ->condition($or);
  }
}

/**
 * Implements hook_og_membership_insert().
 */
function oa_core_og_membership_insert($og_membership) {
  drupal_static_reset('oa_core_node_grants');
  if ($og_membership->entity_type == 'user') {
    oa_core_clear_group_cache(NULL, $og_membership->etid);
  }
}

/**
 * Determine true privacy of a space by checking node grants
 * @param $node object or nid
 * @return TRUE if space is private
 */
function oa_core_get_group_privacy($node) {
  $nid = is_numeric($node) ? $node : $node->nid;
  $query = db_select('node_access', 'n')
    ->fields('n', array(
    'grant_view',
  ))
    ->condition('nid', $nid)
    ->condition('realm', 'all');
  $result = $query
    ->execute()
    ->fetchcol(0);
  return empty($result);
}

/**
 * Utility function to return visibility data for a given node
 * $data['public'] TRUE if node is public, FALSE if private
 * $data['title'] either "Public" or "Private"
 * $data['accessors']['group'] list of groups that can access
 * $data['accessors']['space'] list of spaces that can access
 * $data['accessors']['teams'] list of teams that can access
 * $data['accessors']['users'] list of users that can access
 */
function oa_core_visibility_data($node) {
  $static =& drupal_static(__FUNCTION__, array());
  if (!empty($static[$node->nid])) {
    return $static[$node->nid];
  }
  $data = array();
  $data['published'] = !empty($node->status);
  $data['archived'] = FALSE;
  if (module_exists('flag') && ($flag = flag_get_flag('trash'))) {
    $data['archived'] = $flag
      ->is_flagged($node->nid);
  }
  if ($node->type == OA_SPACE_TYPE || $node->type == OA_GROUP_TYPE) {
    $visibility = field_get_items('node', $node, 'group_access');
    $private = oa_core_get_group_privacy($node);
    $data['public'] = !$private;
    $data['space_public_in_private'] = $private && empty($visibility[0]['value']);
    if (!$data['public'] && ($ids = og_subgroups_parents_load('node', $node->nid)) && !empty($ids['node'])) {
      if ($groups = array_filter(oa_core_get_titles($ids['node'], 'oa_group', 'title', array(
        'link',
      ), TRUE, 0))) {
        $data['accessors']['group'] = array(
          'links' => $groups['links'],
          'label' => t('Groups'),
        );
      }
      if ($spaces = array_filter(oa_core_get_titles($ids['node'], 'oa_space', 'title', array(
        'link',
      ), TRUE, 0))) {
        $data['accessors']['space'] = array(
          'links' => $spaces['links'],
          'label' => t('Spaces'),
        );
      }
    }
  }
  else {
    if ($node->type == OA_SECTION_TYPE) {
      $section_node = $node;
    }
    else {
      $section_reference_field = field_get_items('node', $node, OA_SECTION_FIELD);
      if (isset($section_reference_field[0]['target_id'])) {
        $section_node = node_load($section_reference_field[0]['target_id']);
      }
    }
    if (empty($section_node)) {
      $section_node = $node;
    }
    $space_reference_field = field_get_items('node', $section_node, OA_SPACE_FIELD);
    $space_node = node_load($space_reference_field[0]['target_id']);
    if (empty($space_node)) {
      $data['public'] = TRUE;
    }
    else {
      $space_private = oa_core_get_group_privacy($space_node);
      $visibility = field_get_items('node', $space_node, 'group_access');
      $data['space_public_in_private'] = $space_private && empty($visibility[0]['value']);
      $private = oa_core_get_group_privacy($space_reference_field[0]['target_id']);
      $data['public'] = ($section_node->type != OA_SECTION_TYPE || oa_core_section_is_public($section_node)) && !$private;
      if (!$data['public']) {
        $spaces = _oa_core_build_visibility_links('node', $section_node, OA_GROUP_FIELD, OA_SPACE_TYPE);
        if ($private || !empty($spaces)) {
          $data['accessors']['space'] = array(
            'links' => $spaces + _oa_core_build_visibility_links('node', $section_node, OA_SPACE_FIELD, OA_SPACE_TYPE),
            'label' => t('Spaces'),
          );
        }
        $spaces = _oa_core_build_visibility_links('node', $section_node, OA_GROUP_FIELD, OA_GROUP_TYPE);
        if ($private || !empty($spaces)) {
          $data['accessors']['group'] = array(
            'links' => $spaces + _oa_core_build_visibility_links('node', $section_node, OA_SPACE_FIELD, OA_GROUP_TYPE),
            'label' => t('Groups'),
          );
        }
        $data['accessors']['teams'] = array(
          'links' => _oa_core_build_visibility_links('node', $section_node, OA_TEAM_FIELD),
          'label' => t('Teams'),
        );
        $data['accessors']['users'] = array(
          'links' => _oa_core_build_visibility_links('user', $section_node, OA_USER_FIELD),
          'label' => t('Additional Users'),
        );
      }
    }
  }
  $data['title'] = $data['public'] ? t('Public') : t('Private');
  $static[$node->nid] = $data;
  return $data;
}

/**
 * Helper function, builds links for the various visibility fields on content.
 */
function _oa_core_build_visibility_links($type, $node, $field, $bundle = '') {
  $links = array();
  $nids = array();
  if ($field == OA_SPACE_FIELD) {

    // Get all parent spaces instead of just direct parent
    $spaces = field_get_items('node', $node, $field);
    if (!empty($spaces)) {
      $space = current($spaces);
      $nids = oa_core_get_parents($space['target_id'], $bundle, NODE_PUBLISHED, FALSE, TRUE);

      // Add current space to list
      if ($bundle == OA_SPACE_TYPE) {
        $nids[] = $space['target_id'];
      }
    }
  }
  else {
    $values = field_get_items('node', $node, $field);
    if (!empty($values)) {
      foreach ($values as $value) {
        $nids[] = $value['target_id'];
      }
    }
  }
  if (!empty($nids)) {
    if ($type == 'node') {
      $titles = oa_core_get_titles($nids, $bundle);
      $links = $titles['links'];
    }
    elseif ($type == 'user') {
      $links = array();
      $query = db_select('realname', 'u');
      $query
        ->fields('u', array(
        'uid',
        'realname',
      ))
        ->condition('u.uid', $nids, 'IN');
      $users = $query
        ->execute()
        ->fetchAllAssoc('uid');
      foreach ($users as $uid => $user) {
        $links[] = l($user->realname, "user/" . $uid);
      }
    }
  }
  return $links;
}

/**
 * Helper function to determine access to create nodes of certain taxonomy terms
 * @param $tid
 * @param null $gid
 * @param string $vocab_name
 */
function oa_core_get_taxonomy_term_access($tid, $gid = NULL, $vocab_name = 'space_type') {
  global $user;
  $cache =& drupal_static('oa_core_get_taxonomy_term_access', array());
  $gid = isset($gid) ? $gid : oa_core_get_space_context();
  if (isset($cache[$tid][$gid][$vocab_name])) {
    return $cache[$tid][$gid][$vocab_name];
  }
  $result = FALSE;

  // When checking OG Permission, don't let Admin Group override this since all
  // Space admins typically have Admin Group but we want to limit types of subspaces
  // to be created.
  if (!$gid || !module_exists('oa_subspaces') || $vocab_name == 'section_type' || user_access('administer group') || user_access('create oa_space content') || og_user_access('node', $gid, 'use any oa button space_type', NULL, FALSE, TRUE)) {
    $result = TRUE;
  }
  elseif ($gid && $user->uid) {
    $result = og_user_access('node', $gid, _oa_buttons_perm_name($vocab_name, $tid), NULL, FALSE, TRUE);
  }

  // Allow other modules to override access to terms.
  $context = array(
    'tid' => $tid,
    'gid' => $gid,
    'vocab_name' => $vocab_name,
  );
  drupal_alter('oa_core_get_taxonomy_term_access', $result, $context);
  $cache[$tid][$gid][$vocab_name] = $result;
  return $result;
}

Functions

Namesort descending Description
oa_core_file_entity_access Implements hook_file_entity_access().
oa_core_get_group_privacy Determine true privacy of a space by checking node grants
oa_core_get_taxonomy_term_access Helper function to determine access to create nodes of certain taxonomy terms
oa_core_node_access Implements hook_node_access().
oa_core_node_access_records Implements hook_node_access_records().
oa_core_node_grants Implements hook_node_grants(). Define node access grant realm for Open Atrium sections
oa_core_node_update Implements hook_node_update().
oa_core_oa_core_og_content_needs_rebuild Implements hook_oa_core_og_content_needs_rebuild().
oa_core_og_membership_insert Implements hook_og_membership_insert().
oa_core_og_subgroups_is_parent_private_alter Implements hook_og_subgroups_is_parent_private_alter(). Handle special Atrium case where a private Group Parent does not make a public space private. Only having a private SPACE Parent makes a public space private.
oa_core_query_media_browser_alter Implements hook_query_media_browser_alter(). Add private file access support to media browser
oa_core_section_access Determine access to a Open Atrium Section do NOT use node_load here as it gets called from hook_node_grants() TODO: No longer called from node_grants, but called from tests. Is this still needed?
oa_core_update_access_records Update the node_access_records of the given nodes.
oa_core_visibility_data Utility function to return visibility data for a given node $data['public'] TRUE if node is public, FALSE if private $data['title'] either "Public" or "Private" $data['accessors']['group']…
_oa_core_build_visibility_links Helper function, builds links for the various visibility fields on content.
_oa_core_update_access_records_batch Batch for updating node access records.
_oa_core_update_access_records_batch_finished Called when the batch is finished.
_oa_core_update_access_records_batch_prepare Set up the batch process to update node records.