From b48467c3f8d422bd8d61d0fb35f65f73aa630fcb Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 10 Jan 2024 20:17:44 +0000 Subject: [PATCH] Validate full search text --- database.sql | 1 + doc/database/db_channel.md | 1 + src/Content/Conversation/Entity/Timeline.php | 5 ++++- .../Factory/UserDefinedChannel.php | 1 + .../Repository/UserDefinedChannel.php | 22 +++++++++++++++++-- static/dbstructure.config.php | 1 + 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/database.sql b/database.sql index f184f66819..813c14a994 100644 --- a/database.sql +++ b/database.sql @@ -506,6 +506,7 @@ CREATE TABLE IF NOT EXISTS `channel` ( `media-type` smallint unsigned COMMENT 'Filtered media types', `languages` mediumtext COMMENT 'Desired languages', `publish` boolean COMMENT 'publish channel content', + `valid` boolean COMMENT 'Set, when the full-text-search is valid', PRIMARY KEY(`id`), INDEX `uid` (`uid`), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE diff --git a/doc/database/db_channel.md b/doc/database/db_channel.md index afd65b867c..5b0636dc80 100644 --- a/doc/database/db_channel.md +++ b/doc/database/db_channel.md @@ -20,6 +20,7 @@ Fields | media-type | Filtered media types | smallint unsigned | YES | | NULL | | | languages | Desired languages | mediumtext | YES | | NULL | | | publish | publish channel content | boolean | YES | | NULL | | +| valid | Set, when the full-text-search is valid | boolean | YES | | NULL | | Indexes ------------ diff --git a/src/Content/Conversation/Entity/Timeline.php b/src/Content/Conversation/Entity/Timeline.php index 175971a583..cbb2862eb5 100644 --- a/src/Content/Conversation/Entity/Timeline.php +++ b/src/Content/Conversation/Entity/Timeline.php @@ -64,8 +64,10 @@ class Timeline extends \Friendica\BaseEntity protected $languages; /** @var bool */ protected $publish; + /** @var bool */ + protected $valid; - public function __construct(string $code = null, string $label = null, string $description = null, string $accessKey = null, string $path = null, int $uid = null, string $includeTags = null, string $excludeTags = null, string $fullTextSearch = null, int $mediaType = null, int $circle = null, array $languages = null, bool $publish = null) + public function __construct(string $code = null, string $label = null, string $description = null, string $accessKey = null, string $path = null, int $uid = null, string $includeTags = null, string $excludeTags = null, string $fullTextSearch = null, int $mediaType = null, int $circle = null, array $languages = null, bool $publish = null, bool $valid = null) { $this->code = $code; $this->label = $label; @@ -80,5 +82,6 @@ class Timeline extends \Friendica\BaseEntity $this->circle = $circle; $this->languages = $languages; $this->publish = $publish; + $this->valid = $valid; } } diff --git a/src/Content/Conversation/Factory/UserDefinedChannel.php b/src/Content/Conversation/Factory/UserDefinedChannel.php index d4798cd6c7..08a092205c 100644 --- a/src/Content/Conversation/Factory/UserDefinedChannel.php +++ b/src/Content/Conversation/Factory/UserDefinedChannel.php @@ -51,6 +51,7 @@ final class UserDefinedChannel extends Timeline implements ICanCreateFromTableRo $row['circle'] ?? null, $row['languages'] ?? null, $row['publish'] ?? null, + $row['valid'] ?? null, ); } } diff --git a/src/Content/Conversation/Repository/UserDefinedChannel.php b/src/Content/Conversation/Repository/UserDefinedChannel.php index e7b32255fe..bb8ad02f6b 100644 --- a/src/Content/Conversation/Repository/UserDefinedChannel.php +++ b/src/Content/Conversation/Repository/UserDefinedChannel.php @@ -134,6 +134,7 @@ class UserDefinedChannel extends \Friendica\BaseRepository 'media-type' => $Channel->mediaType, 'languages' => serialize($Channel->languages), 'publish' => $Channel->publish, + 'valid' => $this->isValid($Channel->fullTextSearch), ]; if ($Channel->code) { @@ -149,6 +150,18 @@ class UserDefinedChannel extends \Friendica\BaseRepository return $Channel; } + private function isValid(string $searchtext): bool + { + if ($searchtext == '') { + return true; + } + + $this->db->insert('check-full-text-search', ['pid' => getmypid(), 'searchtext' => $searchtext], Database::INSERT_UPDATE); + $result = $this->db->select('check-full-text-search', [], ["`pid` = ? AND MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE)", getmypid(), $this->escapeKeywords($searchtext)]); + $this->db->delete('check-full-text-search', ['pid' => getmypid()]); + return $result !== false; + } + /** * Checks, if one of the user defined channels matches with the given search text * @todo Combine all the full text statements in a single search text to improve the performance. @@ -214,7 +227,7 @@ class UserDefinedChannel extends \Friendica\BaseRepository $uids = []; - $condition = ['uid' => $channelUids]; + $condition = ['uid' => $channelUids, 'valid' => true]; if (!$relayMode) { $condition = DBA::mergeConditions($condition, ["`full-text-search` != ?", '']); } else { @@ -298,11 +311,16 @@ class UserDefinedChannel extends \Friendica\BaseRepository } private function inFulltext(string $fullTextSearch): bool + { + return $this->db->exists('check-full-text-search', ["`pid` = ? AND MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE)", getmypid(), $this->escapeKeywords($fullTextSearch)]); + } + + private function escapeKeywords(string $fullTextSearch): string { foreach (Engagement::KEYWORDS as $keyword) { $fullTextSearch = preg_replace('~(' . $keyword . ':.[\w@\.-]+)~', '"$1"', $fullTextSearch); } - return $this->db->exists('check-full-text-search', ["`pid` = ? AND MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE)", getmypid(), $fullTextSearch]); + return $fullTextSearch; } private function getUserCondition() diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index ded1295adf..cb5ea1c23f 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -564,6 +564,7 @@ return [ "media-type" => ["type" => "smallint unsigned", "comment" => "Filtered media types"], "languages" => ["type" => "mediumtext", "comment" => "Desired languages"], "publish" => ["type" => "boolean", "comment" => "publish channel content"], + "valid" => ["type" => "boolean", "comment" => "Set, when the full-text-search is valid"], ], "indexes" => [ "PRIMARY" => ["id"],