Version 4.7.0

This commit is contained in:
Neo committed 2025-12-19 16:00:35 -08:00
1 parent 517a5e1f70
commit 8ba7d43898
1933 files changed
+65613 -11332

No files matched your search

+173 -15
View File
@@ -69,7 +69,12 @@ class _Query extends \IPS\Content\Search\Query
parent::__construct( $member );
$this->url = $url;
}
/**
* @var bool Stores whether or not any content type needs to be limited by the latest comment
*/
protected $lastCommentMustBeTrue = false;
/**
* Filter by multiple content types
*
@@ -198,11 +203,14 @@ class _Query extends \IPS\Content\Search\Query
/* Only last comment? */
if ( $filter->onlyLastComment )
{
/* Set this for when the search JSON is built */
$this->lastCommentMustBeTrue = true;
$conditions[] = array(
'term' => array( 'index_is_last_comment' => true )
);
}
/* Put it together */
if( \count( $conditions ) )
{
@@ -215,7 +223,7 @@ class _Query extends \IPS\Content\Search\Query
{
$this->filters[] = array(
'bool' => array(
( $type ? 'should' : 'must_not' ) => array( $contentFilterConditions )
( $type ? 'should' : 'must_not' ) => $contentFilterConditions
)
);
}
@@ -363,7 +371,79 @@ class _Query extends \IPS\Content\Search\Query
/* Return for daisy chaining */
return $this;
}
/**
* Stores the "more like this" Content object for search()
* @param null
*/
protected $moreLikeThis = NULL;
/**
* Filter by more like this
* @param \IPS\Content\Searchable $object
*/
public function filterByMoreLikeThis( \IPS\Content\Searchable $object )
{
$index = new \IPS\Content\Search\Elastic\Index( $this->url );
$this->moreLikeThis = $index->getIndexId( ( $object instanceof \IPS\Content\Item and $object::$firstCommentRequired ) ? $object->firstComment() : $object );
/* Some container types cannot be cached */
$classes = [];
$conditions = [];
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter', FALSE ) as $object )
{
$classes = array_merge( $object->classes, $classes );
}
/* Some nodes have complex permissions, so avoid any permission issues by not selecting these */
foreach( $classes as $itemClass )
{
if ( isset( $itemClass::$containerNodeClass ) )
{
$containerClass = $itemClass::$containerNodeClass;
$blockIds = [];
if ( $customNodes = $containerClass::customPermissionNodes() )
{
foreach ( $customNodes as $key => $ids )
{
if ( $key !== 'count' )
{
$blockIds = array_merge( $blockIds, $ids );
}
}
}
if ( \count( $blockIds ) )
{
$conditions[] = array(
'bool' => array(
'filter' => array(
array(
'terms' => array( 'index_container_class' => [ $containerClass ] )
),
array(
'terms' => array( 'index_container_id' => $blockIds )
),
)
)
);
}
if ( \count( $conditions ) )
{
foreach( $conditions as $condition )
{
$this->mustNot[] = $condition;
}
}
}
}
/* Only show non-hidden and approved items */
$this->setHiddenFilter( static::HIDDEN_VISIBLE );
}
/**
* Filter by container class
*
@@ -558,9 +638,7 @@ class _Query extends \IPS\Content\Search\Query
if ( $includeMembers and $followed = iterator_to_array( \IPS\Db::i()->select( 'follow_rel_id', 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_member_id=?', 'core', 'member', $this->member->member_id ), 'follow_rel_id asc' ) ) )
{
$conditions[] = array(
array(
'terms' => array( 'index_author' => $followed )
)
'terms' => array( 'index_author' => $followed )
);
}
@@ -799,7 +877,35 @@ class _Query extends \IPS\Content\Search\Query
return $this;
}
/**
* Filter by solved
*
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
public function filterBySolved()
{
$this->filters[] = array(
'term' => array( 'index_item_solved' => 1 )
);
return $this;
}
/**
* Filter by Unsolved
*
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
public function filterByUnsolved()
{
$this->filters[] = array(
'term' => array( 'index_item_solved' => 0 )
);
return $this;
}
/**
* Filter by start date
*
@@ -922,7 +1028,35 @@ class _Query extends \IPS\Content\Search\Query
return $this;
}
/**
* Debug by itemId, used for debugging purposes only
* @note No permission checks run, do not use in production
* @param $itemId
* @return void
*/
public function debugByItemId( $itemId )
{
$array = array(
'query' => [
'term' => [
'index_item_id' => [
'value' => \intval( $itemId )
]
]
],
'sort' => $this->sort ?: array(),
'from' => 0,
'size' => 50,
);
$json = json_encode( $array, JSON_PARTIAL_OUTPUT_ON_ERROR );
return \IPS\Content\Search\Elastic\Index::request( $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' ) )->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( $json )->decodeJson();
}
/**
* Search
*
@@ -1017,6 +1151,12 @@ class _Query extends \IPS\Content\Search\Query
)
)
);
/* If we're not searching with a term, then just show the title record, not comments */
if ( $term === NULL and ! $this->lastCommentMustBeTrue )
{
$must[] = ['exists' => ['field' => 'index_title']];
}
}
/* Put that with the rest of the conditions */
@@ -1050,7 +1190,25 @@ class _Query extends \IPS\Content\Search\Query
$filters[] = array( 'term' => array( 'index_hidden' => $this->hiddenStatuses ) );
}
}
$searchUrl = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' );
if ( $this->moreLikeThis )
{
$must[] = [
'more_like_this' => [
'fields' => [ 'index_title' ],
'like' => [ '_index' => \IPS\Settings::i()->search_elastic_index, '_id' => $this->moreLikeThis ],
'min_term_freq' => 1,
'max_query_terms' => 12,
'min_word_length' => 3,
]
];
/* Let's enforce a relatively short timeout to prevent slow ES server from dragging down topics */
$searchUrl = $searchUrl->setQueryString( 'timeout', '3s' );
}
/* Peform the search */
try
{
@@ -1062,9 +1220,9 @@ class _Query extends \IPS\Content\Search\Query
'filter' => $filters
)
);
/* Add the time decay */
if ( \IPS\Settings::i()->search_decay_factor and !$this->sort )
if ( \IPS\Settings::i()->search_decay_factor and !$this->sort and ! $this->sort )
{
$query = array(
'function_score' => array(
@@ -1081,7 +1239,7 @@ class _Query extends \IPS\Content\Search\Query
}
/* Add the self boost */
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id and !$this->sort )
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id and !$this->sort and ! $this->moreLikeThis )
{
$query = array(
'function_score' => array(
@@ -1117,10 +1275,10 @@ class _Query extends \IPS\Content\Search\Query
}
/* 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();
$return = \IPS\Content\Search\Elastic\Index::request( $searchUrl )->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( $json )->decodeJson();
if ( isset( $return['error'] ) )
{
\IPS\Log::log( print_r( $return['error'], TRUE ), 'elasticsearch' );
\IPS\Log::log( print_r( array_merge( $array, ['error' => $return['error'] ] ), TRUE ), 'elasticsearch' );
return new \IPS\Content\Search\Results( array(), 0 );
}