From ec7eb9d83a86ba1b63c2f9d0a68c2afd25c5d7fd Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Dec 2019 17:15:41 -0500 Subject: [PATCH 1/4] Rename BaseSearchModule::performSearch to performContactSearch to remove purpose confusion --- src/Module/BaseSearchModule.php | 4 ++-- src/Module/Search/Directory.php | 2 +- src/Module/Search/Index.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Module/BaseSearchModule.php b/src/Module/BaseSearchModule.php index 9766c000cc..96692b0b2d 100644 --- a/src/Module/BaseSearchModule.php +++ b/src/Module/BaseSearchModule.php @@ -22,7 +22,7 @@ use Friendica\Util\Strings; class BaseSearchModule extends BaseModule { /** - * Performs a search with an optional prefix + * Performs a contact search with an optional prefix * * @param string $search Search query * @param string $prefix A optional prefix (e.g. @ or !) for searching @@ -31,7 +31,7 @@ class BaseSearchModule extends BaseModule * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function performSearch($search, $prefix = '') + public static function performContactSearch($search, $prefix = '') { $a = self::getApp(); $config = $a->getConfig(); diff --git a/src/Module/Search/Directory.php b/src/Module/Search/Directory.php index b18847afe9..e3515713f5 100644 --- a/src/Module/Search/Directory.php +++ b/src/Module/Search/Directory.php @@ -31,6 +31,6 @@ class Directory extends BaseSearchModule $a->page['aside'] .= Widget::findPeople(); $a->page['aside'] .= Widget::follow(); - return self::performSearch($search); + return self::performContactSearch($search); } } diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 7c52c7e79d..8921c07aa6 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -88,7 +88,7 @@ class Index extends BaseSearchModule } if (strpos($search, '@') === 0 || strpos($search, '!') === 0) { - return self::performSearch($search); + return self::performContactSearch($search); } if (parse_url($search, PHP_URL_SCHEME) != '') { @@ -109,9 +109,9 @@ class Index extends BaseSearchModule $tag = true; break; case 'contacts': - return self::performSearch($search, '@'); + return self::performContactSearch($search, '@'); case 'forums': - return self::performSearch($search, '!'); + return self::performContactSearch($search, '!'); } } From 1c9cb42d98b3792d70b0a081003d0912dcc62037 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Dec 2019 17:17:27 -0500 Subject: [PATCH 2/4] Move search term emptiness check before content checks in Search\Index --- src/Module/Search/Index.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 8921c07aa6..691fc3ec89 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -82,6 +82,10 @@ class Index extends BaseSearchModule '$content' => HTML::search($search, 'search-box', false) ]); + if (!$search) { + return $o; + } + if (strpos($search, '#') === 0) { $tag = true; $search = substr($search, 1); @@ -115,10 +119,6 @@ class Index extends BaseSearchModule } } - if (!$search) { - return $o; - } - $tag = $tag || Config::get('system', 'only_tag_search'); // Here is the way permissions work in the search module... From 016507f346e604617ffe1938ef8133bb91b03928 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Dec 2019 17:34:57 -0500 Subject: [PATCH 3/4] Use BaseURL::redirect instead of deprecated App->internalRedirect in Search\Index --- src/Module/Search/Index.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 691fc3ec89..29ebeffd06 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -3,6 +3,7 @@ namespace Friendica\Module\Search; use Friendica\App\Arguments; +use Friendica\App\BaseURL; use Friendica\Content\Nav; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; @@ -96,11 +97,15 @@ class Index extends BaseSearchModule } if (parse_url($search, PHP_URL_SCHEME) != '') { - $id = Item::fetchByLink($search); - if (!empty($id)) { - $item = Item::selectFirst(['guid'], ['id' => $id]); + /** @var BaseURL $baseURL */ + $baseURL = self::getClass(BaseURL::class); + + // Post URL search + $item_id = Item::fetchByLink($search); + if (!empty($item_id)) { + $item = Item::selectFirst(['guid'], ['id' => $item_id]); if (DBA::isResult($item)) { - self::getApp()->internalRedirect('display/' . $item['guid']); + $baseURL->redirect('display/' . $item['guid']); } } } From a11b47f93d2691c0ce2048f85949c2f035a7ee6d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Dec 2019 17:38:04 -0500 Subject: [PATCH 4/4] Add profile URL search - Move post URL search to private method in Module\Search\Index --- src/Module/Search/Index.php | 107 +++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 29ebeffd06..010f0a790a 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -16,6 +16,7 @@ use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\Database\DBA; +use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Model\Term; use Friendica\Module\BaseSearchModule; @@ -38,6 +39,9 @@ class Index extends BaseSearchModule throw $e; } + /** @var BaseURL $baseURL */ + $baseURL = self::getClass(BaseURL::class); + if (Config::get('system', 'permit_crawling') && !Session::isAuthenticated()) { // Default values: // 10 requests are "free", after the 11th only a call per minute is allowed @@ -92,23 +96,13 @@ class Index extends BaseSearchModule $search = substr($search, 1); } + self::tryRedirectToProfile($baseURL, $search); + if (strpos($search, '@') === 0 || strpos($search, '!') === 0) { return self::performContactSearch($search); } - if (parse_url($search, PHP_URL_SCHEME) != '') { - /** @var BaseURL $baseURL */ - $baseURL = self::getClass(BaseURL::class); - - // Post URL search - $item_id = Item::fetchByLink($search); - if (!empty($item_id)) { - $item = Item::selectFirst(['guid'], ['id' => $item_id]); - if (DBA::isResult($item)) { - $baseURL->redirect('display/' . $item['guid']); - } - } - } + self::tryRedirectToPost($baseURL, $search); if (!empty($_GET['search-option'])) { switch ($_GET['search-option']) { @@ -202,4 +196,91 @@ class Index extends BaseSearchModule return $o; } + + /** + * Tries to redirect to a local profile page based on the input. + * + * This method separates logged in and anonymous users. Logged in users can trigger contact probes to import + * non-existing contacts while anonymous users can only trigger a local lookup. + * + * Formats matched: + * - @user@domain + * - user@domain + * - Any fully-formed URL + * + * @param BaseURL $baseURL + * @param string $search + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + private static function tryRedirectToProfile(BaseURL $baseURL, string $search) + { + $isUrl = parse_url($search, PHP_URL_SCHEME) !== ''; + $isAddr = preg_match('/^@?([a-z0-9.-_]+@[a-z0-9.-_:]+)$/i', trim($search), $matches); + + if (!$isUrl && !$isAddr) { + return; + } + + if ($isAddr) { + $search = $matches[1]; + } + + if (local_user()) { + // User-specific contact URL/address search + $contact_id = Contact::getIdForURL($search, local_user()); + if (!$contact_id) { + // User-specific contact URL/address search and probe + $contact_id = Contact::getIdForURL($search); + } + } else { + // Cheaper local lookup for anonymous users, no probe + if ($isAddr) { + $contact = Contact::selectFirst(['id' => 'cid'], ['addr' => $search, 'uid' => 0]); + } else { + $contact = Contact::getDetailsByURL($search, 0, ['cid' => 0]); + } + + if (DBA::isResult($contact)) { + $contact_id = $contact['cid']; + } + } + + if (!empty($contact_id)) { + $baseURL->redirect('contact/' . $contact_id); + } + } + + /** + * Fetch/search a post by URL and redirects to its local representation if it was found. + * + * @param BaseURL $baseURL + * @param string $search + * @throws HTTPException\InternalServerErrorException + */ + private static function tryRedirectToPost(BaseURL $baseURL, string $search) + { + if (parse_url($search, PHP_URL_SCHEME) == '') { + return; + } + + if (local_user()) { + // Post URL search + $item_id = Item::fetchByLink($search, local_user()); + if (!$item_id) { + // If the user-specific search failed, we search and probe a public post + $item_id = Item::fetchByLink($search); + } + } else { + // Cheaper local lookup for anonymous users, no probe + $item_id = Item::searchByLink($search); + } + + if (!empty($item_id)) { + $item = Item::selectFirst(['guid'], ['id' => $item_id]); + if (DBA::isResult($item)) { + $baseURL->redirect('display/' . $item['guid']); + } + } + } }