Version 4.3.6
This commit is contained in:
1 parent
fe1acf984a
commit
1a0c7fd3c2
609 files changed
+14707
-5726
No files matched your search
@@ -125,6 +125,21 @@ class _ContentFilter
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* init() adds in review classes, comment classes, etc. But if we want to filter based on just the comment class, we need this method
|
||||
*
|
||||
* @param string $class The class
|
||||
* @return \IPS\Content\Search\ContentFilter
|
||||
*/
|
||||
public static function initWithSpecificClass( $class )
|
||||
{
|
||||
$obj = new static;
|
||||
$obj->classes = array( $class );
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only include results in containers
|
||||
*
|
||||
|
||||
@@ -47,7 +47,10 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$this->url->request()->delete();
|
||||
$this->url->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->put( json_encode( array(
|
||||
'mappings' => array(
|
||||
'settings' => array(
|
||||
'max_result_window' => \IPS\Settings::i()->search_index_maxresults
|
||||
),
|
||||
'mappings' => array(
|
||||
'content' => array(
|
||||
'properties' => array(
|
||||
'index_class' => array( 'type' => 'keyword' ),
|
||||
@@ -145,17 +148,87 @@ class _Index extends \IPS\Content\Search\Index
|
||||
try
|
||||
{
|
||||
$class = get_class( $object );
|
||||
|
||||
/* Do not allow hidden comments to be flagged as latest */
|
||||
if ( $object instanceof \IPS\Content\Comment and $indexData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 ) //
|
||||
|
||||
$existingData = NULL;
|
||||
$existingIndexId = NULL;
|
||||
$resetLastComment = FALSE;
|
||||
|
||||
try
|
||||
{
|
||||
$indexData['index_is_last_comment'] = false;
|
||||
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $object ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get()->decodeJson();
|
||||
if ( $r['found'] )
|
||||
{
|
||||
$existingData = $r['_source'];
|
||||
$existingIndexId = $r['_id'];
|
||||
}
|
||||
}
|
||||
|
||||
catch( \Exception $e ) { }
|
||||
|
||||
if ( $object instanceof \IPS\Content\Comment and $existingIndexId and $existingData['index_is_last_comment'] and $indexData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 )
|
||||
{
|
||||
/* We do not allow hidden or needing approval comments to become flagged as the last comment as this means users without hidden view permission never see the item in an item only stream */
|
||||
$indexData['index_is_last_comment'] = false;
|
||||
|
||||
$resetLastComment = TRUE;
|
||||
}
|
||||
else if ( $indexData['index_is_last_comment'] and $indexData['index_item_id'] )
|
||||
{
|
||||
$classes = array( $class );
|
||||
|
||||
/* If this is the latest comment, unflag what was set before on both item and comment */
|
||||
if ( $object instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$itemClass = $object::$itemClass;
|
||||
if ( ! $itemClass::$firstCommentRequired )
|
||||
{
|
||||
$classes[] = $itemClass;
|
||||
}
|
||||
|
||||
if ( isset( $itemClass::$reviewClass ) )
|
||||
{
|
||||
$classes[] = $itemClass::$reviewClass;
|
||||
}
|
||||
}
|
||||
else if ( $object instanceof \IPS\Content\Item )
|
||||
{
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
$classes[] = $class::$commentClass;
|
||||
}
|
||||
if ( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$classes[] = $class::$reviewClass;
|
||||
}
|
||||
}
|
||||
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_is_last_comment = false;",
|
||||
'lang' => 'painless'
|
||||
),
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_class' => $classes
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_item_id' => $indexData['index_item_id']
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
) ) );
|
||||
}
|
||||
|
||||
/* Insert into index */
|
||||
$r = $this->url
|
||||
->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $object ) )
|
||||
->request()
|
||||
->request( \IPS\LONG_REQUEST_TIMEOUT )
|
||||
->setHeaders( array( 'Content-Type' => 'application/json' ) )
|
||||
->put( json_encode( $indexData ) );
|
||||
|
||||
@@ -174,6 +247,11 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
\IPS\Log::log( $e, 'elasticsearch' );
|
||||
}
|
||||
|
||||
if ( $resetLastComment )
|
||||
{
|
||||
$this->resetLastComment( array( $indexData['index_class'] ), $indexData['index_item_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,7 +276,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$classes[] = $class::$reviewClass;
|
||||
}
|
||||
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_views += ". intval( $count ) . ";",
|
||||
'lang' => 'painless'
|
||||
@@ -221,6 +299,44 @@ class _Index extends \IPS\Content\Search\Index
|
||||
)
|
||||
) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out any tasks associated with the search index method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearTasks()
|
||||
{
|
||||
try
|
||||
{
|
||||
/* This request *intentionally* goes to _tasks and not (ourpath)/_tasks */
|
||||
$response = $this->url->setPath( '/_tasks' )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->get()->decodeJson();
|
||||
|
||||
foreach( $response['nodes'] as $nodeId => $nodeData )
|
||||
{
|
||||
foreach( $nodeData['tasks'] as $taskId => $taskData )
|
||||
{
|
||||
/* We only need to worry about deleting parent tasks */
|
||||
if( isset( $taskData['parent_task_id'] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the task is cancellable it isn't finished yet */
|
||||
if( $taskData['cancellable'] === TRUE )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->url->setPath( '/.tasks/task' . $taskId )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'elasticsearch' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the comment / review counts for an item
|
||||
@@ -296,7 +412,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$updates[] = "ctx._source.index_is_last_comment = ( ctx._id == '{$lastCommentIndexId}' );";
|
||||
}
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => implode( ' ', $updates ),
|
||||
'lang' => 'painless'
|
||||
@@ -356,7 +472,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
$commentClass = $class::$commentClass;
|
||||
$response = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$response = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
@@ -379,7 +495,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
if ( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$reviewClass = $class::$reviewClass;
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
@@ -455,13 +571,13 @@ class _Index extends \IPS\Content\Search\Index
|
||||
);
|
||||
}
|
||||
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'query' => $query
|
||||
) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'query' => array(
|
||||
'term' => array(
|
||||
'index_class' => $class
|
||||
@@ -558,7 +674,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
|
||||
if ( count( $updates ) )
|
||||
{
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => implode( ' ', $updates ),
|
||||
'lang' => 'painless'
|
||||
@@ -578,7 +694,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
)
|
||||
);
|
||||
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_permissions.add( 'm.' + ctx._source.index_author );",
|
||||
'lang' => 'painless'
|
||||
@@ -595,7 +711,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$conditions['must'][] = array(
|
||||
'term' => array(
|
||||
'index_item_author' => '0'
|
||||
'index_hidden' => 0
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -603,14 +719,14 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$conditions['must'][] = array(
|
||||
'term' => array(
|
||||
'index_item_author' => '2'
|
||||
'index_hidden' => 2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_permissions = " . intval( $newHiddenStatus ) . ";",
|
||||
'inline' => "ctx._source.index_hidden = " . intval( $newHiddenStatus ) . ";",
|
||||
'lang' => 'painless'
|
||||
),
|
||||
'query' => array(
|
||||
@@ -706,7 +822,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'query' => array(
|
||||
'range' => array(
|
||||
'index_date_updated' => array(
|
||||
@@ -739,7 +855,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
try
|
||||
{
|
||||
/* Remove the flag */
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_is_last_comment = false;",
|
||||
'lang' => 'painless'
|
||||
@@ -763,76 +879,66 @@ class _Index extends \IPS\Content\Search\Index
|
||||
) ) );
|
||||
|
||||
/* Get the latest comment */
|
||||
$latest = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_class' => $classes
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_item_id' => $indexItemId
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_hidden' => 0
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
'sort' => array(
|
||||
array(
|
||||
'index_date_created' => 'desc'
|
||||
)
|
||||
),
|
||||
'size' => 1
|
||||
) ) )->decodeJson();
|
||||
|
||||
/* If we got it... */
|
||||
if ( $latest['hits']['total'] )
|
||||
$itemClass = NULL;
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
$result = $latest['hits']['hits'][0];
|
||||
|
||||
/* Set that it is the latest comment */
|
||||
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/' . $result['_type'] . '/' . $result['_id'] . '/_update' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'doc' => array(
|
||||
'index_is_last_comment' => true
|
||||
)
|
||||
) ) );
|
||||
|
||||
/* And set the updated time on the main item (done as _update_by_query because it might not exist if the first comment is required) */
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_date_updated = " . intval( $latest['_source']['index_date_updated'] ) ."; ctx._source.index_date_commented = " . intval( $latest['_source']['index_date_commented'] ) .";",
|
||||
'lang' => 'painless'
|
||||
),
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_class' => $classes
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_item_id' => $indexItemId
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_object_id' => $indexItemId
|
||||
)
|
||||
),
|
||||
if ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
$itemClass = $class;
|
||||
break;
|
||||
}
|
||||
elseif ( isset( $class::$itemClass ) )
|
||||
{
|
||||
$itemClass = $class::$itemClass;
|
||||
}
|
||||
}
|
||||
if ( $itemClass )
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $itemClass::load( $indexItemId );
|
||||
|
||||
if ( $lastComment = $item->comments( 1, 0, 'date', 'desc', NULL, FALSE ) )
|
||||
{
|
||||
/* Set that it is the latest comment */
|
||||
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $lastComment ) . '/_update' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'doc' => array(
|
||||
'index_is_last_comment' => true
|
||||
)
|
||||
)
|
||||
)
|
||||
) ) );
|
||||
) ) );
|
||||
|
||||
/* And set the updated time on the main item (done as _update_by_query because it might not exist if the first comment is required) */
|
||||
$indexDataForLastComment = $this->indexData( $lastComment );
|
||||
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
|
||||
'script' => array(
|
||||
'inline' => "ctx._source.index_date_updated = " . intval( $indexDataForLastComment['index_date_updated'] ) ."; ctx._source.index_date_commented = " . intval( $indexDataForLastComment['index_date_commented'] ) .";",
|
||||
'lang' => 'painless'
|
||||
),
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'must' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_class' => $classes
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_item_id' => $indexItemId
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_object_id' => $indexItemId
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
) ) );
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
@@ -852,23 +958,45 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
try
|
||||
{
|
||||
$results = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
|
||||
'query' => array(
|
||||
'bool' => array(
|
||||
'filter' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_item_index_id' => $itemIndexIds
|
||||
),
|
||||
/* Set the query */
|
||||
$query = array(
|
||||
'bool' => array(
|
||||
'filter' => array(
|
||||
array(
|
||||
'terms' => array(
|
||||
'index_item_index_id' => $itemIndexIds
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_author' => $member->member_id
|
||||
)
|
||||
),
|
||||
array(
|
||||
'term' => array(
|
||||
'index_author' => $member->member_id
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/* Get the count */
|
||||
$count = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
|
||||
'size' => 0,
|
||||
'query' => $query
|
||||
) ) )->decodeJson();
|
||||
if ( !$count['hits']['total'] )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/* Now get the unique item ids */
|
||||
$results = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
|
||||
'aggs' => array(
|
||||
'itemIds' => array(
|
||||
'terms' => array(
|
||||
'field' => 'index_item_index_id',
|
||||
'size' => $count['hits']['total']
|
||||
)
|
||||
)
|
||||
),
|
||||
'query' => $query
|
||||
) ) )->decodeJson();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
@@ -878,9 +1006,12 @@ class _Index extends \IPS\Content\Search\Index
|
||||
}
|
||||
|
||||
$iPostedIn = array();
|
||||
foreach ( $results['hits']['hits'] as $result )
|
||||
foreach ( $results['aggregations']['itemIds']['buckets'] as $result )
|
||||
{
|
||||
$iPostedIn[] = $result['_source']['index_item_index_id'];
|
||||
if ( $result['doc_count'] )
|
||||
{
|
||||
$iPostedIn[] = $result['key'];
|
||||
}
|
||||
}
|
||||
|
||||
return $iPostedIn;
|
||||
|
||||
@@ -906,6 +906,12 @@ class _Query extends \IPS\Content\Search\Query
|
||||
*/
|
||||
public function search( $term = NULL, $tags = NULL, $method = 1, $operator = NULL )
|
||||
{
|
||||
/* If we're looking for more results than we can fetch, we don't need to ask Elastic Search */
|
||||
if( ( $this->offset + $this->resultsToGet ) >= \IPS\Settings::i()->search_index_maxresults )
|
||||
{
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
|
||||
$operator = $operator ?: \IPS\Settings::i()->search_default_operator;
|
||||
$must = array();
|
||||
$filters = $this->filters;
|
||||
@@ -924,11 +930,11 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$term = trim( $term, '"' );
|
||||
if ( $method & static::TERM_TITLES_ONLY )
|
||||
{
|
||||
$searchConditions[] = array( 'match_phrase' => array( 'index_title' => array( 'query' => $term ), 'analyzer' => 'standard' ) );
|
||||
$searchConditions[] = array( 'match_phrase' => array( 'index_title' => array( 'query' => $term ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$searchConditions[] = array( 'multi_match' => array( 'query' => $term, 'fields' => array( 'index_content', $titleField ), 'type' => 'phrase', 'analyzer' => 'standard' ) );
|
||||
$searchConditions[] = array( 'multi_match' => array( 'query' => $term, 'fields' => array( 'index_content', $titleField ), 'type' => 'phrase' ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -995,6 +1001,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
/* Peform the search */
|
||||
try
|
||||
{
|
||||
/* Initial query */
|
||||
$query = array(
|
||||
'bool' => array(
|
||||
'must' => $must,
|
||||
@@ -1003,6 +1010,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
)
|
||||
);
|
||||
|
||||
/* Add the time decay */
|
||||
if ( \IPS\Settings::i()->search_decay_factor and !$this->sort )
|
||||
{
|
||||
$query = array(
|
||||
@@ -1017,8 +1025,9 @@ class _Query extends \IPS\Content\Search\Query
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id )
|
||||
|
||||
/* Add the self boost */
|
||||
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id and !$this->sort )
|
||||
{
|
||||
$query = array(
|
||||
'function_score' => array(
|
||||
@@ -1033,25 +1042,37 @@ class _Query extends \IPS\Content\Search\Query
|
||||
);
|
||||
}
|
||||
|
||||
$return = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
|
||||
/* Build the JSON and validate it. Use JSON_PARTIAL_OUTPUT_ON_ERROR in case someone has used an unencodable value as
|
||||
the term, and check json_encode() didn't return FALSE (which it may do on error) as a sanity check against
|
||||
sending a blank query, which would return everything in the index */
|
||||
$array = array(
|
||||
'query' => $query,
|
||||
'sort' => $this->sort ?: array(),
|
||||
'from' => $this->offset,
|
||||
'size' => $this->resultsToGet,
|
||||
) ) )->decodeJson();
|
||||
);
|
||||
|
||||
$json = json_encode( $array, JSON_PARTIAL_OUTPUT_ON_ERROR );
|
||||
if ( $json === FALSE )
|
||||
{
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
|
||||
/* Make the call! */
|
||||
$return = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( $json )->decodeJson();
|
||||
if ( isset( $return['error'] ) )
|
||||
{
|
||||
\IPS\Log::log( print_r( $return['error'], TRUE ), 'elasticsearch' );
|
||||
return new \IPS\Content\Search\Results( array(), 0 );
|
||||
}
|
||||
|
||||
|
||||
/* Set results */
|
||||
return new \IPS\Content\Search\Results( array_map( function( $hit ) {
|
||||
$indexData = $hit['_source'];
|
||||
$indexData['index_permissions'] = implode( ',', $indexData['index_permissions'] );
|
||||
$indexData['index_tags'] = $indexData['index_tags'] ? implode( ',', $indexData['index_tags'] ) : NULL;
|
||||
return $indexData;
|
||||
}, $return['hits']['hits'] ), $return['hits']['total'] );
|
||||
}, $return['hits']['hits'] ), $return['hits']['total'] <= \IPS\Settings::i()->search_index_maxresults ? $return['hits']['total'] : (int) \IPS\Settings::i()->search_index_maxresults );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
{
|
||||
if ( \IPS\Settings::i()->search_method == 'elastic' )
|
||||
{
|
||||
static::$instance = new \IPS\Content\Search\Elastic\Index( \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
static::$instance = new \IPS\Content\Search\Elastic\Index( \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -59,7 +59,7 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
{
|
||||
if ( \IPS\Settings::i()->search_method == 'elastic' )
|
||||
{
|
||||
return new \IPS\Content\Search\Elastic\MassIndexer( \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
return new \IPS\Content\Search\Elastic\MassIndexer( \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -104,6 +104,30 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Index a single items comments and reviews if applicable.
|
||||
*
|
||||
* @param \IPS\Content\Searchable $object The item to index
|
||||
* @return void
|
||||
*/
|
||||
public function indexSingleItem( \IPS\Content\Searchable $object )
|
||||
{
|
||||
try
|
||||
{
|
||||
$idColumn = $object::$databaseColumnId;
|
||||
if ( isset( $object::$commentClass ) AND is_subclass_of( $object::$commentClass, 'IPS\Content\Searchable' ) )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'IndexSingleItem', array( 'class' => $object::$commentClass, 'id' => $object->$idColumn, 'title' => $object->mapped('title'), 'url' => (string) $object->url() ), 5, TRUE );
|
||||
}
|
||||
|
||||
if ( isset( $object::$reviewClass ) AND is_subclass_of( $object::$reviewClass, 'IPS\Content\Searchable' ) )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'IndexSingleItem', array( 'class' => $object::$reviewClass, 'id' => $object->$idColumn, 'title' => $object->mapped('title'), 'url' => (string) $object->url() ), 5, TRUE );
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $e ) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index data
|
||||
*
|
||||
@@ -138,9 +162,19 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
$itemClass = $class::$itemClass;
|
||||
if ( $itemClass::$firstCommentRequired and $object->isFirst() )
|
||||
{
|
||||
$title = $object->item()->searchIndexTitle();
|
||||
$tags = ( $object->item() instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? implode( ',', array_filter( $object->item()->tags() ) ) : NULL;
|
||||
$prefix = ( $object->item() instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? $object->item()->prefix() : NULL;
|
||||
try
|
||||
{
|
||||
$item = $object->item();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
/* Comment has no working item, return */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$title = $item->searchIndexTitle();
|
||||
$tags = ( $item instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? implode( ',', array_filter( $item->tags() ) ) : NULL;
|
||||
$prefix = ( $item instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? $item->prefix() : NULL;
|
||||
$isForItem = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -375,6 +409,16 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
{
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out any tasks associated with the search index method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearTasks()
|
||||
{
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the search ID for an item
|
||||
|
||||
@@ -484,8 +484,10 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
if ( $cutoff )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_item_id IN( ? )', \IPS\Db::i()->select( 'index_item_id', 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) ) ) );
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) ) ) );
|
||||
$prefix = \IPS\Db::i()->prefix;
|
||||
|
||||
\IPS\Db::i()->query( "DELETE {$prefix}core_search_index_item_map FROM {$prefix}core_search_index_item_map, {$prefix}core_search_index WHERE {$prefix}core_search_index_item_map.index_item_id={$prefix}core_search_index.index_item_id AND index_date_updated < " . $cutoff->getTimestamp() );
|
||||
\IPS\Db::i()->query( "DELETE {$prefix}core_search_index_tags FROM {$prefix}core_search_index_tags, {$prefix}core_search_index WHERE {$prefix}core_search_index_tags.index_id={$prefix}core_search_index.index_id AND index_date_updated < " . $cutoff->getTimestamp() );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) );
|
||||
}
|
||||
else
|
||||
|
||||
@@ -94,7 +94,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
foreach ( $contentFilters as $filter )
|
||||
{
|
||||
$clause = array();
|
||||
if ( $type )
|
||||
if ( $type and $filter->itemClass )
|
||||
{
|
||||
$this->itemClasses[] = $filter->itemClass;
|
||||
}
|
||||
@@ -116,16 +116,19 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$clause[] = \IPS\Db::i()->in( 'index_container_id', $filter->containerIds, $filter->containerIdFilter === FALSE );
|
||||
}
|
||||
|
||||
$itemClass = $filter->itemClass;
|
||||
if ( isset( $itemClass::$containerNodeClass ) )
|
||||
if ( $filter->itemClass )
|
||||
{
|
||||
$containerClass = $itemClass::$containerNodeClass;
|
||||
$unsearchableIds = $containerClass::unsearchableNodeIds();
|
||||
|
||||
if ( $unsearchableIds != NULL )
|
||||
$itemClass = $filter->itemClass;
|
||||
if ( isset( $itemClass::$containerNodeClass ) )
|
||||
{
|
||||
$clause[] = \IPS\Db::i()->in( 'index_container_id', $unsearchableIds, TRUE );
|
||||
}
|
||||
$containerClass = $itemClass::$containerNodeClass;
|
||||
$unsearchableIds = $containerClass::unsearchableNodeIds();
|
||||
|
||||
if ( $unsearchableIds != NULL )
|
||||
{
|
||||
$clause[] = \IPS\Db::i()->in( 'index_container_id', $unsearchableIds, TRUE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Are we excluding certain container classes? */
|
||||
|
||||
@@ -54,7 +54,7 @@ abstract class _Query
|
||||
{
|
||||
if ( \IPS\Settings::i()->search_method == 'elastic' )
|
||||
{
|
||||
return new \IPS\Content\Search\Elastic\Query( $member ?: \IPS\Member::loggedIn(), \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
return new \IPS\Content\Search\Elastic\Query( $member ?: \IPS\Member::loggedIn(), \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -119,8 +119,13 @@ class _Content extends \IPS\Content\Search\Result
|
||||
*/
|
||||
public function addToRssFeed( \IPS\Xml\Rss $document )
|
||||
{
|
||||
$class = $this->indexData['index_class'];
|
||||
$object = $class::load( $this->indexData['index_object_id'] );
|
||||
$document->addItem( $object instanceof \IPS\Content\Comment ? $object->item()->mapped('title') : $object->mapped('title'), $object->url(), $this->indexData['index_content'], \IPS\DateTime::ts( $this->indexData['index_date_created'] ) );
|
||||
try
|
||||
{
|
||||
$class = $this->indexData['index_class'];
|
||||
$object = $class::load( $this->indexData['index_object_id'] );
|
||||
$document->addItem( $object instanceof \IPS\Content\Comment ? $object->item()->searchIndexTitle() : $object->searchIndexTitle(), $object->url(), $this->indexData['index_content'], \IPS\DateTime::ts( $this->indexData['index_date_created'] ) );
|
||||
}
|
||||
/* If the search result was orphaned, let us continue */
|
||||
catch( \OutOfRangeException $e ){}
|
||||
}
|
||||
}
|
||||
@@ -546,7 +546,7 @@ class _Results extends \ArrayIterator
|
||||
{
|
||||
$extraItem = array_pop( $extraItems );
|
||||
|
||||
$mergeList = array_merge( array( $urlToThing ), $extraItem->getMergeData() );
|
||||
$mergeList = array_filter( array_merge( array( $urlToThing ), $extraItem->getMergeData() ) );
|
||||
$listToDisplay = $mergeList;
|
||||
|
||||
if( count( $mergeList ) > 3 )
|
||||
|
||||
Reference in new issue
Block a user