diff --git a/app/src/Repository/MsgrcptSearchRepository.php b/app/src/Repository/MsgrcptSearchRepository.php index c8a2a047..ebc03a0a 100644 --- a/app/src/Repository/MsgrcptSearchRepository.php +++ b/app/src/Repository/MsgrcptSearchRepository.php @@ -278,15 +278,26 @@ private function addRecipientsCondition(QueryBuilder $queryBuilder, User $user): private function addSearchKeyCondition(QueryBuilder $queryBuilder, string $searchKey): void { - $potentialEmails = Email::extractEmailsFromText($searchKey); - $foundUserEmails = $this->userRepository->searchUsersByEmails($potentialEmails); + $potentialEmails = Email::extractEmailsFromText($searchKey, looseMode: true); + $foundUserEmails = $this->userRepository->searchEmails($potentialEmails); $allUserEmails = array_unique($foundUserEmails); + // Get the list of "potential emails" that matched a real email in the + // database to exclude them from the boolean search below. + $termsToExclude = []; + foreach ($potentialEmails as $potentialEmail) { + foreach ($allUserEmails as $email) { + if (str_contains($email, $potentialEmail)) { + $termsToExclude[] = $potentialEmail; + } + } + } + // Create the boolean search string by excluding the terms that matched // a user's email. The emails will be used to search against the // recipient or the sender emails, while the other terms will be used // to perform a boolean search against subject, from and the message's id. - $booleanSearch = Search::textToMariadbBooleanSearch($searchKey, excludeTerms: $allUserEmails); + $booleanSearch = Search::textToMariadbBooleanSearch($searchKey, excludeTerms: $termsToExclude); // Add the boolean search condition. if ($booleanSearch) { diff --git a/app/src/Repository/UserRepository.php b/app/src/Repository/UserRepository.php index 69e7ab8c..90326f7b 100644 --- a/app/src/Repository/UserRepository.php +++ b/app/src/Repository/UserRepository.php @@ -305,17 +305,23 @@ public function getUsersWithRoleAndMessageCounts(User $user, ?Domain $domain = n * @param string[] $emails * @return string[] */ - public function searchUsersByEmails(array $emails): array + public function searchEmails(array $emails): array { if (empty($emails)) { return []; } $queryBuilder = $this->createQueryBuilder('u'); - $queryBuilder->select('u.email') - ->where("u.email IN (:emails) and u.roles is not null") - ->setParameter('emails', $emails); + $queryBuilder->select('u.email'); + $queryBuilder->where("u.roles is not null"); + $expr = new Expr\Orx(); + foreach ($emails as $key => $email) { + $expr->add("u.email LIKE :email{$key}"); + $queryBuilder->setParameter("email{$key}", "%{$email}%"); + } + + $queryBuilder->andWhere($expr); return $queryBuilder->getQuery()->getSingleColumnResult(); } diff --git a/app/src/Util/Email.php b/app/src/Util/Email.php index 1bdbfd1d..c46d2cde 100644 --- a/app/src/Util/Email.php +++ b/app/src/Util/Email.php @@ -7,9 +7,13 @@ class Email /** * Return whether the email address is valid or not */ - public static function validate(string $email): bool + public static function validate(string $email, bool $looseMode = false): bool { - return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; + if ($looseMode) { + return str_contains($email, '@'); + } else { + return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; + } } /** @@ -17,13 +21,13 @@ public static function validate(string $email): bool * * @return string[] */ - public static function extractEmailsFromText(string $text): array + public static function extractEmailsFromText(string $text, bool $looseMode = false): array { $terms = preg_split('/\s+/', trim($text), -1, PREG_SPLIT_NO_EMPTY) ?: []; $emails = []; foreach ($terms as $term) { - if (self::validate($term)) { + if (self::validate($term, $looseMode)) { $emails[] = $term; } } diff --git a/app/src/Util/Search.php b/app/src/Util/Search.php index 0a47276b..546b68d9 100644 --- a/app/src/Util/Search.php +++ b/app/src/Util/Search.php @@ -23,10 +23,13 @@ public static function textToMariadbBooleanSearch(string $text, array $excludeTe }); // Sanitize the terms to perform a boolean search. - $safeTerms = array_map(static function ($term) { - $safe = preg_replace('/[+\-><()~*"@]+/', ' ', $term); - return trim($safe ?: ''); - }, $terms); + $safeTerms = []; + foreach ($terms as $term) { + $safeTerm = preg_replace('/[+\-><()~*"@\.]+/', ' ', $term); + $safeTerm = trim($safeTerm ?: ''); + $explodedSafeTerm = explode(' ', $safeTerm); + $safeTerms = array_merge($safeTerms, $explodedSafeTerm); + } // Remove stop words and words with less than 3 chars because searching // for them will return no results (as they are not indexed by MariaDB).