<?php
// $Id: apachesolr_nodeaccess.module,v 1.1.2.14 2010/06/16 20:43:40 jpmckinney Exp $

/**
 * Implementation of apachesolr_update_index
 */
function apachesolr_nodeaccess_apachesolr_update_index(&$document, $node, $namespace) {
  static $account;

  if (!isset($account)) {
    // Load the anonymous user.
    $account = drupal_anonymous_user();
  }

  if (!node_access('view', $node, $account)) {
    // Get node access grants.
    $result = db_query('SELECT * FROM {node_access} WHERE (nid = 0 OR nid = %d) AND grant_view = 1', $node->nid);
    while ($grant = db_fetch_object($result)) {
      $key = 'nodeaccess_' . apachesolr_site_hash() . '_' . $grant->realm;
      $document->setMultiValue($key, $grant->gid);
    }
  }
  else {
    // Add the generic view grant if we are not using
    // node access or the node is viewable by anonymous users.
    $document->setMultiValue('nodeaccess_all', 0);
  }
}

/**
 * Creates a Solr query for a given user
 *
 * @param $account an account to get grants for and build a solr query
 *
 * @throws Exception
 */
function _apachesolr_nodeaccess_build_subquery($account) {
  if (!user_access('access content', $account)) {
    throw new Exception('No access');
  }
  $node_access_query = apachesolr_drupal_query();
  if (empty($node_access_query)) {
    throw new Exception('No query object in apachesolr_nodeaccess');
  }
  if (user_access('administer nodes', $account)) {
    // Access all content from the current site, or public content.
    $node_access_query->add_filter('nodeaccess_all', 0);
    $node_access_query->add_filter('hash', apachesolr_site_hash());
  }
  else {
    // Get node access grants.
    $grants = node_access_grants('view', $account);
    foreach ($grants as $realm => $gids) {
      foreach ($gids as $gid) {
        $node_access_query->add_filter('nodeaccess_' . apachesolr_site_hash() . '_' . $realm, $gid);
      }
    }
    $node_access_query->add_filter('nodeaccess_all', 0);
  }
  return $node_access_query;
}

/**
 * Implementation of hook_apachesolr_modify_query().
 */
function apachesolr_nodeaccess_apachesolr_modify_query(&$query, &$params, $caller) {
  global $user;
  try {
    $subquery = _apachesolr_nodeaccess_build_subquery($user);
  }
  catch (Exception $e) {
    $query = NULL;
    watchdog("apachesolr_nodeaccess", 'User %name (UID:!uid) cannot search: @message', array('%name' => $user->name, '!uid' => $user->uid, '@message' => $e->getMessage()));
    return;
  }

  if (!empty($subquery)) {
    $query->add_subquery($subquery, 'OR');
  }
}

/**
 * Implementation of hook_nodeapi().
 *
 * Listen to this hook to find out when a node is being saved.
 */
function apachesolr_nodeaccess_nodeapi(&$node, $op) {
  switch ($op) {
    case 'insert':
    case 'update':
      // hook_nodeapi() is called before hook_node_access_records() in node_save().
      $node->apachesolr_nodeaccess_ignore = 1;
      break;
  }
}

/**
 * Implementation of hook_node_access_records().
 *
 * Listen to this hook to find out when a node needs to be re-indexed
 * for its node access grants.
 */
function apachesolr_nodeaccess_node_access_records($node) {
  // node_access_needs_rebuild() will usually be TRUE during a
  // full rebuild.
  if (empty($node->apachesolr_nodeaccess_ignore) && !node_access_needs_rebuild()) {
    // Only one node is being changed - mark for re-indexing.
    apachesolr_mark_node($node->nid);
  }
}

/**
 * Implementation of hook_form_alter().
 */
function apachesolr_nodeaccess_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'node_configure_rebuild_confirm') {
    $form['#submit'][] = 'apachesolr_nodeaccess_rebuild_nodeaccess';
  }
}

/**
 * Force Solr to do a total re-index when node access rules change.
 *
 * This is unfortunate because not every node is going to be affected, but
 * there is little we can do.
 */
function apachesolr_nodeaccess_rebuild_nodeaccess(&$form, $form_state) {
  drupal_set_message(t('Solr search index will be rebuilt.'));
  node_access_needs_rebuild(TRUE);
  apachesolr_clear_last_index();
}

function apachesolr_nodeaccess_enable() {
  drupal_set_message(t('Your content <a href="@url">must be re-indexed</a> before Apache Solr node access will be functional on searches.', array('@url' => url('admin/settings/apachesolr/index'))), 'warning');
}
