diff --git a/includes/processor_node_access.inc b/includes/processor_node_access.inc new file mode 100644 index 0000000..3b2da91 --- /dev/null +++ b/includes/processor_node_access.inc @@ -0,0 +1,117 @@ +index->item_type == 'node') { + // Load all notes as once. + foreach ($items as $nid => &$item) { + $nids[$nid] = $nid; + } + $nodes = node_load_multiple($nids); + + foreach ($nodes as $nid => $node) { + // Check whether all users have access to the node. + if (!node_access('view', $node, $account)) { + // Get node access grants. + $result = db_query('SELECT * FROM {node_access} WHERE (nid = 0 OR nid = :nid) AND grant_view = 1', array(':nid' => $node->nid)); + + // Store all grants together with it's realms in the item. + foreach ($result as $grant) { + if (!isset($item['access_node_' . $grant->realm])) { + $item['access_node_' . $grant->realm] = array( + 'name' => 'access_node_' . $grant->realm, + 'value' => array(), + // @todo: Doesn't a boolean makes more sense here? + 'type' => 'list', + 'original' => 'list', + ); + } + + $item['node_access_' . $grant->realm][] = $grant->gid; + } + } + else { + // Add the generic view grant if we are not using + // node access or the node is viewable by anonymous users. + // We assume we'll never have an entity with the name '_all'. + $item['access_node__all'] = array( + 'name' => 'access_node__all', + 'value' => 1, + // @todo: Doesn't a boolean makes more sense here? + 'type' => 'integer', + 'original' => 'integer', + ); + } + } + } + } + + /** + * Alter search query to add filters for node access. + */ + public function preprocessSearchQuery(SearchApiQuery $query) { + parent::preprocessSearchQuery($query); + + $account = $GLOBALS['user']; + + if ($query->index->item_type == 'node') { + try { + $accessQuery = $this->buildAccessQuery($account); + if ($accessQuery) { + $query->filter($accessQuery); + } + } + catch (SearchApiException $e) { + watchdog("search_api", 'User %name (UID:!uid) cannot search: @message', array('%name' => $account->name, '!uid' => $account->uid, '@message' => $e->getMessage())); + } + } + } + + /** + * Build a node access subquery. + * + * @return SearchApiQueryFilter + */ + function buildAccessQuery($account) { + if (!user_access('access content', $account)) { + throw new SearchApiException(t('The current user has no node access, uid: @uid', array('@uid' => $account->uid))); + } + + // Only filter for user which don't have full node access. + if (!user_access('bypass node access', $account)) { + $nodeAccessQuery = new SearchApiQueryFilter('OR'); + // Get node access grants. + $grants = node_access_grants('view', $account); + foreach ($grants as $realm => $gids) { + foreach ($gids as $gid) { + $nodeAccessQuery->condition('access_node_' . $realm, $gid); + } + } + return $nodeAccessQuery; + } + } +} + diff --git a/search_api.info b/search_api.info index 7d3b55b..fdc0681 100644 --- a/search_api.info +++ b/search_api.info @@ -20,6 +20,7 @@ files[] = includes/index_entity.inc files[] = includes/processor.inc files[] = includes/processor_html_filter.inc files[] = includes/processor_ignore_case.inc +files[] = includes/processor_node_access.inc files[] = includes/processor_stopwords.inc files[] = includes/processor_tokenizer.inc files[] = includes/query.inc diff --git a/search_api.module b/search_api.module index 249298b..18617b4 100644 --- a/search_api.module +++ b/search_api.module @@ -765,6 +765,14 @@ function search_api_search_api_processor_info() { 'class' => 'SearchApiStopWords', 'weight' => 30, ); + $processors['search_api_node_access'] = array( + 'name' => t('Node access'), + // @TODO: This description sucks. + 'description' => t('This processor adds node access + to node indexes by retrieving some information from the node module.'), + 'class' => 'SearchApiNodeAccess', + 'weight' => 40, + ); return $processors; }