Merge pull request #12152 from nupplaphil/mod/msearch

Move mod/mod/msearch & mod/match to src/Module
This commit is contained in:
Hypolite Petovan 2022-11-09 16:55:25 -05:00 committed by GitHub
commit 59b48c2d84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 363 additions and 251 deletions

View File

@ -1,132 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use Friendica\App;
use Friendica\Content\Widget;
use Friendica\Core\Renderer;
use Friendica\Core\Search;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Module\Contact as ModuleContact;
/**
* Controller for /match.
*
* It takes keywords from your profile and queries the directory server for
* matching keywords from other profiles.
*
* @param App $a App
*
* @return string
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws Exception
*/
function match_content(App $a)
{
if (!DI::userSession()->getLocalUserId()) {
return '';
}
DI::page()['aside'] .= Widget::findPeople();
DI::page()['aside'] .= Widget::follow();
$_SESSION['return_path'] = DI::args()->getCommand();
$profile = Profile::getByUID(DI::userSession()->getLocalUserId());
if (!DBA::isResult($profile)) {
return '';
}
if (!$profile['pub_keywords'] && (!$profile['prv_keywords'])) {
DI::sysmsg()->addNotice(DI::l10n()->t('No keywords to match. Please add keywords to your profile.'));
return '';
}
$params = [];
$tags = trim($profile['pub_keywords'] . ' ' . $profile['prv_keywords']);
if (DI::mode()->isMobile()) {
$limit = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network',
DI::config()->get('system', 'itemspage_network_mobile'));
} else {
$limit = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_network',
DI::config()->get('system', 'itemspage_network'));
}
$params['s'] = $tags;
$params['n'] = 100;
$entries = [];
foreach ([Search::getGlobalDirectory(), DI::baseUrl()] as $server) {
if (empty($server)) {
continue;
}
$msearch = json_decode(DI::httpClient()->post($server . '/msearch', $params)->getBody());
if (!empty($msearch)) {
$entries = match_get_contacts($msearch, $entries, $limit);
}
}
if (empty($entries)) {
DI::sysmsg()->addInfo(DI::l10n()->t('No matches'));
}
$tpl = Renderer::getMarkupTemplate('contact/list.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => DI::l10n()->t('Profile Match'),
'$contacts' => array_slice($entries, 0, $limit),
]);
return $o;
}
function match_get_contacts($msearch, $entries, $limit)
{
if (empty($msearch->results)) {
return $entries;
}
foreach ($msearch->results as $profile) {
if (!$profile) {
continue;
}
// Already known contact
$contact = Contact::getByURL($profile->url, null, ['rel'], DI::userSession()->getLocalUserId());
if (!empty($contact) && in_array($contact['rel'], [Contact::FRIEND, Contact::SHARING])) {
continue;
}
$contact = Contact::getByURLForUser($profile->url, DI::userSession()->getLocalUserId());
if (!empty($contact)) {
$entries[$contact['id']] = ModuleContact::getContactTemplateVars($contact);
}
if (count($entries) == $limit) {
break;
}
}
return $entries;
}

View File

@ -1,64 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use Friendica\App;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Util\Proxy;
function msearch_post(App $a)
{
$search = $_POST['s'] ?? '';
$perpage = intval(($_POST['n'] ?? 0) ?: 80);
$page = intval(($_POST['p'] ?? 0) ?: 1);
$startrec = ($page - 1) * $perpage;
$total = 0;
$results = [];
if (!strlen($search)) {
$output = ['total' => 0, 'items_page' => $perpage, 'page' => $page, 'results' => $results];
System::jsonExit($output);
}
$total = 0;
$condition = ["`net-publish` AND MATCH(`pub_keywords`) AGAINST (?)", $search];
$total = DBA::count('owner-view', $condition);
$search_stmt = DBA::select('owner-view', ['pub_keywords', 'name', 'nickname', 'uid'], $condition, ['limit' => [$startrec, $perpage]]);
while ($search_result = DBA::fetch($search_stmt)) {
$results[] = [
'name' => $search_result['name'],
'url' => DI::baseUrl() . '/profile/' . $search_result['nickname'],
'photo' => User::getAvatarUrl($search_result, Proxy::SIZE_THUMB),
'tags' => str_replace([',', ' '], [' ', ' '], $search_result['pub_keywords'])
];
}
DBA::close($search_stmt);
$output = ['total' => $total, 'items_page' => $perpage, 'page' => $page, 'results' => $results];
System::jsonExit($output);
}

View File

@ -0,0 +1,186 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Module\Contact;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\Widget;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\Renderer;
use Friendica\Core\Search;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Database\Database;
use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Module\Contact as ModuleContact;
use Friendica\Module\Response;
use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/**
* It takes keywords from your profile and queries the directory server for
* matching keywords from other profiles.
*/
class MatchInterests extends BaseModule
{
const FETCH_PER_PAGE = 100;
/** @var IHandleUserSessions */
protected $session;
/** @var Database */
protected $database;
/** @var SystemMessages */
protected $systemMessages;
/** @var App\Page */
protected $page;
/** @var App\Mode */
protected $mode;
/** @var IManageConfigValues */
protected $config;
/** @var IManagePersonalConfigValues */
protected $pConfig;
/** @var ICanSendHttpRequests */
protected $httpClient;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, Database $database, SystemMessages $systemMessages, App\Page $page, App\Mode $mode, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, ICanSendHttpRequests $httpClient, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session;
$this->database = $database;
$this->systemMessages = $systemMessages;
$this->page = $page;
$this->mode = $mode;
$this->config = $config;
$this->pConfig = $pConfig;
$this->httpClient = $httpClient;
}
protected function content(array $request = []): string
{
if (!$this->session->getLocalUserId()) {
$this->systemMessages->addNotice($this->t('Permission denied.'));
$this->baseUrl->redirect('login&return_path=match');
}
$profile = Profile::getByUID($this->session->getLocalUserId());
if (empty($profile)) {
$this->logger->warning('Couldn\'t find Profile for user id in session.', ['uid' => $this->session->getLocalUserId()]);
throw new InternalServerErrorException($this->t('Invalid request.'));
}
$this->page['aside'] .= Widget::findPeople();
$this->page['aside'] .= Widget::follow();
if (empty($profile['pub_keywords']) && empty($profile['prv_keywords'])) {
$this->systemMessages->addNotice($this->t('No keywords to match. Please add keywords to your profile.'));
return '';
}
if ($this->mode->isMobile()) {
$limit = $this->pConfig->get($this->session->getLocalUserId(), 'system', 'itemspage_mobile_network')
?? $this->config->get('system', 'itemspage_network_mobile');
} else {
$limit = $this->pConfig->get($this->session->getLocalUserId(), 'system', 'itemspage_network')
?? $this->config->get('system', 'itemspage_network');
}
$searchParameters = [
's' => trim($profile['pub_keywords'] . ' ' . $profile['prv_keywords']),
'n' => self::FETCH_PER_PAGE,
];
$entries = [];
foreach ([Search::getGlobalDirectory(), $this->baseUrl] as $server) {
if (empty($server)) {
continue;
}
$result = $this->httpClient->post($server . '/search/user/tags', $searchParameters);
if (!$result->isSuccess()) {
// try legacy endpoint
$result = $this->httpClient->post($server . '/msearch', $searchParameters);
if (!$result->isSuccess()) {
$this->logger->notice('Search-Endpoint not available for server.', ['server' => $server]);
continue;
}
}
$entries = $this->parseContacts(json_decode($result->getBody()), $entries, $limit);
}
if (empty($entries)) {
$this->systemMessages->addNotice($this->t('No matches'));
}
$tpl = Renderer::getMarkupTemplate('contact/list.tpl');
return Renderer::replaceMacros($tpl, [
'$title' => $this->t('Profile Match'),
'$contacts' => array_slice($entries, 0, $limit),
]);
}
/**
* parses the JSON result and adds the new entries until the limit is reached
*
* @param $jsonResult
* @param array $entries
* @param int $limit
*
* @return array the new entries array
*/
protected function parseContacts($jsonResult, array $entries, int $limit): array
{
if (empty($jsonResult->results)) {
return $entries;
}
foreach ($jsonResult->results as $profile) {
if (!$profile) {
continue;
}
// Already known contact
$contact = Contact::getByURL($profile->url, null, ['rel'], $this->session->getLocalUserId());
if (!empty($contact) && in_array($contact['rel'], [Contact::FRIEND, Contact::SHARING])) {
continue;
}
$contact = Contact::getByURLForUser($profile->url, $this->session->getLocalUserId());
if (!empty($contact)) {
$entries[$contact['id']] = ModuleContact::getContactTemplateVars($contact);
}
if (count($entries) == $limit) {
break;
}
}
return $entries;
}
}

107
src/Module/Search/Tags.php Normal file
View File

@ -0,0 +1,107 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Module\Search;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Database\Database;
use Friendica\Model\User;
use Friendica\Module\Response;
use Friendica\Util\Profiler;
use Friendica\Util\Proxy;
use Psr\Log\LoggerInterface;
/**
* Search users because of their public/private tags
*/
class Tags extends BaseModule
{
const DEFAULT_ITEMS_PER_PAGE = 80;
/** @var Database */
protected $database;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, Database $database, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->database = $database;
}
protected function rawContent(array $request = [])
{
$tags = $request['s'] ?? '';
$perPage = intval($request['n'] ?? self::DEFAULT_ITEMS_PER_PAGE);
$page = intval($request['p'] ?? 1);
$startRec = ($page - 1) * $perPage;
$results = [];
if (empty($tags)) {
System::jsonExit([
'total' => 0,
'items_page' => $perPage,
'page' => $page,
'results' => $results,
]);
}
$condition = [
"`net-publish` AND MATCH(`pub_keywords`) AGAINST (?)",
$tags
];
$totalCount = $this->database->count('owner-view', $condition);
if ($totalCount === 0) {
System::jsonExit([
'total' => 0,
'items_page' => $perPage,
'page' => $page,
'results' => $results,
]);
}
$searchStmt = $this->database->select('owner-view',
['pub_keywords', 'name', 'nickname', 'uid'],
$condition,
['limit' => [$startRec, $perPage]]);
while ($searchResult = $this->database->fetch($searchStmt)) {
$results[] = [
'name' => $searchResult['name'],
'url' => $this->baseUrl . '/profile/' . $searchResult['nickname'],
'photo' => User::getAvatarUrl($searchResult, Proxy::SIZE_THUMB),
];
}
$this->database->close($searchStmt);
System::jsonExit([
'total' => $totalCount,
'items_page' => $perPage,
'page' => $page,
'results' => $results,
]);
}
}

View File

@ -92,7 +92,7 @@ interface ICanSendHttpRequests
* Send POST request to an URL * Send POST request to an URL
* *
* @param string $url URL to post * @param string $url URL to post
* @param mixed $params array of POST variables * @param mixed $params POST variables (if an array is passed, it will automatically set as formular parameters)
* @param array $headers HTTP headers * @param array $headers HTTP headers
* @param int $timeout The timeout in seconds, default system config value or 60 seconds * @param int $timeout The timeout in seconds, default system config value or 60 seconds
* *
@ -107,6 +107,7 @@ interface ICanSendHttpRequests
* @param string $url Url to send to * @param string $url Url to send to
* @param array $opts (optional parameters) associative array with: * @param array $opts (optional parameters) associative array with:
* 'body' => (mixed) setting the body for sending data * 'body' => (mixed) setting the body for sending data
* 'form_params' => (array) Associative array of form field names to values
* 'accept_content' => (string array) supply Accept: header with 'accept_content' as the value * 'accept_content' => (string array) supply Accept: header with 'accept_content' as the value
* 'timeout' => int Timeout in seconds, default system config value or 60 seconds * 'timeout' => int Timeout in seconds, default system config value or 60 seconds
* 'cookiejar' => path to cookie jar file * 'cookiejar' => path to cookie jar file

View File

@ -140,6 +140,10 @@ class HttpClient implements ICanSendHttpRequests
$conf[RequestOptions::BODY] = $opts[HttpClientOptions::BODY]; $conf[RequestOptions::BODY] = $opts[HttpClientOptions::BODY];
} }
if (!empty($opts[HttpClientOptions::FORM_PARAMS])) {
$conf[RequestOptions::FORM_PARAMS] = $opts[HttpClientOptions::FORM_PARAMS];
}
if (!empty($opts[HttpClientOptions::AUTH])) { if (!empty($opts[HttpClientOptions::AUTH])) {
$conf[RequestOptions::AUTH] = $opts[HttpClientOptions::AUTH]; $conf[RequestOptions::AUTH] = $opts[HttpClientOptions::AUTH];
} }
@ -205,7 +209,11 @@ class HttpClient implements ICanSendHttpRequests
{ {
$opts = []; $opts = [];
$opts[HttpClientOptions::BODY] = $params; if (!is_array($params)) {
$opts[HttpClientOptions::BODY] = $params;
} else {
$opts[HttpClientOptions::FORM_PARAMS] = $params;
}
if (!empty($headers)) { if (!empty($headers)) {
$opts[HttpClientOptions::HEADERS] = $headers; $opts[HttpClientOptions::HEADERS] = $headers;

View File

@ -59,9 +59,13 @@ class HttpClientOptions
const VERIFY = 'verify'; const VERIFY = 'verify';
/** /**
* body: (mixed) Setting the body for sending data * body: (string) Setting the body for sending data
*/ */
const BODY = RequestOptions::BODY; const BODY = RequestOptions::BODY;
/**
* form_params: (array) Associative array of form field names to values
*/
const FORM_PARAMS = RequestOptions::FORM_PARAMS;
/** /**
* auth: (array) Authentication settings for specific requests * auth: (array) Authentication settings for specific requests
*/ */

View File

@ -367,27 +367,28 @@ return [
'/compose[/{type}]' => [Module\Item\Compose::class, [R::GET, R::POST]], '/compose[/{type}]' => [Module\Item\Compose::class, [R::GET, R::POST]],
'/contact' => [ '/contact' => [
'[/]' => [Module\Contact::class, [R::GET]], '[/]' => [Module\Contact::class, [R::GET]],
'/{id:\d+}[/]' => [Module\Contact\Profile::class, [R::GET, R::POST]], '/{id:\d+}[/]' => [Module\Contact\Profile::class, [R::GET, R::POST]],
'/{id:\d+}/{action:block|ignore|update|updateprofile}' '/{id:\d+}/{action:block|ignore|update|updateprofile}'
=> [Module\Contact\Profile::class, [R::GET]], => [Module\Contact\Profile::class, [R::GET]],
'/{id:\d+}/advanced' => [Module\Contact\Advanced::class, [R::GET, R::POST]], '/{id:\d+}/advanced' => [Module\Contact\Advanced::class, [R::GET, R::POST]],
'/{id:\d+}/conversations' => [Module\Contact\Conversations::class, [R::GET]], '/{id:\d+}/conversations' => [Module\Contact\Conversations::class, [R::GET]],
'/{id:\d+}/contacts[/{type}]' => [Module\Contact\Contacts::class, [R::GET]], '/{id:\d+}/contacts[/{type}]' => [Module\Contact\Contacts::class, [R::GET]],
'/{id:\d+}/media' => [Module\Contact\Media::class, [R::GET]], '/{id:\d+}/media' => [Module\Contact\Media::class, [R::GET]],
'/{id:\d+}/posts' => [Module\Contact\Posts::class, [R::GET]], '/{id:\d+}/posts' => [Module\Contact\Posts::class, [R::GET]],
'/{id:\d+}/revoke' => [Module\Contact\Revoke::class, [R::GET, R::POST]], '/{id:\d+}/revoke' => [Module\Contact\Revoke::class, [R::GET, R::POST]],
'/archived' => [Module\Contact::class, [R::GET]], '/archived' => [Module\Contact::class, [R::GET]],
'/batch' => [Module\Contact::class, [R::GET, R::POST]], '/batch' => [Module\Contact::class, [R::GET, R::POST]],
'/blocked' => [Module\Contact::class, [R::GET]], '/blocked' => [Module\Contact::class, [R::GET]],
'/follow' => [Module\Contact\Follow::class, [R::GET, R::POST]], '/follow' => [Module\Contact\Follow::class, [R::GET, R::POST]],
'/hidden' => [Module\Contact::class, [R::GET]], '/hidden' => [Module\Contact::class, [R::GET]],
'/hovercard' => [Module\Contact\Hovercard::class, [R::GET]], '/hovercard' => [Module\Contact\Hovercard::class, [R::GET]],
'/ignored' => [Module\Contact::class, [R::GET]], '/ignored' => [Module\Contact::class, [R::GET]],
'/pending' => [Module\Contact::class, [R::GET]], '/match' => [Module\Contact\MatchInterests::class, [R::GET]],
'/redir/{id:\d+}' => [Module\Contact\Redir::class, [R::GET]], '/pending' => [Module\Contact::class, [R::GET]],
'/suggestions' => [Module\Contact\Suggestions::class, [R::GET]], '/redir/{id:\d+}' => [Module\Contact\Redir::class, [R::GET]],
'/unfollow' => [Module\Contact\Unfollow::class, [R::GET, R::POST]], '/suggestions' => [Module\Contact\Suggestions::class, [R::GET]],
'/unfollow' => [Module\Contact\Unfollow::class, [R::GET, R::POST]],
], ],
'/credits' => [Module\Credits::class, [R::GET]], '/credits' => [Module\Credits::class, [R::GET]],
@ -571,10 +572,11 @@ return [
'/salmon/{nickname}' => [Module\OStatus\Salmon::class, [ R::POST]], '/salmon/{nickname}' => [Module\OStatus\Salmon::class, [ R::POST]],
'/search' => [ '/search' => [
'[/]' => [Module\Search\Index::class, [R::GET]], '[/]' => [Module\Search\Index::class, [R::GET ]],
'/acl' => [Module\Search\Acl::class, [R::GET, R::POST]], '/acl' => [Module\Search\Acl::class, [R::GET, R::POST]],
'/saved/add' => [Module\Search\Saved::class, [R::GET]], '/saved/add' => [Module\Search\Saved::class, [R::GET ]],
'/saved/remove' => [Module\Search\Saved::class, [R::GET]], '/saved/remove' => [Module\Search\Saved::class, [R::GET ]],
'/user/tags' => [Module\Search\Tags::class, [ R::POST]],
], ],
'/receive' => [ '/receive' => [

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2022.12-dev\n" "Project-Id-Version: 2022.12-dev\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-09 06:29-0500\n" "POT-Creation-Date: 2022-11-09 21:27+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -47,12 +47,12 @@ msgstr ""
#: src/Module/Calendar/Event/Show.php:54 src/Module/Calendar/Export.php:62 #: src/Module/Calendar/Event/Show.php:54 src/Module/Calendar/Export.php:62
#: src/Module/Calendar/Show.php:64 src/Module/Contact/Advanced.php:60 #: src/Module/Calendar/Show.php:64 src/Module/Contact/Advanced.php:60
#: src/Module/Contact/Follow.php:86 src/Module/Contact/Follow.php:158 #: src/Module/Contact/Follow.php:86 src/Module/Contact/Follow.php:158
#: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 #: src/Module/Contact/Match.php:69 src/Module/Contact/Suggestions.php:54
#: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112 #: src/Module/Contact/Unfollow.php:66 src/Module/Contact/Unfollow.php:80
#: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38 #: src/Module/Contact/Unfollow.php:112 src/Module/Delegation.php:118
#: src/Module/FriendSuggest.php:57 src/Module/Group.php:40 #: src/Module/FollowConfirm.php:38 src/Module/FriendSuggest.php:57
#: src/Module/Group.php:83 src/Module/Invite.php:42 src/Module/Invite.php:131 #: src/Module/Group.php:40 src/Module/Group.php:83 src/Module/Invite.php:42
#: src/Module/Notifications/Notification.php:76 #: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76
#: src/Module/Notifications/Notification.php:107 #: src/Module/Notifications/Notification.php:107
#: src/Module/OStatus/Repair.php:60 src/Module/Profile/Attachment/Upload.php:97 #: src/Module/OStatus/Repair.php:60 src/Module/Profile/Attachment/Upload.php:97
#: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55 #: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55
@ -436,18 +436,6 @@ msgstr ""
msgid "Your password has been changed at %s" msgid "Your password has been changed at %s"
msgstr "" msgstr ""
#: mod/match.php:62
msgid "No keywords to match. Please add keywords to your profile."
msgstr ""
#: mod/match.php:93 src/Module/BaseSearch.php:119
msgid "No matches"
msgstr ""
#: mod/match.php:98
msgid "Profile Match"
msgstr ""
#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:289 #: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:289
msgid "New Message" msgid "New Message"
msgstr "" msgstr ""
@ -5524,6 +5512,10 @@ msgstr ""
msgid "Forum Search - %s" msgid "Forum Search - %s"
msgstr "" msgstr ""
#: src/Module/BaseSearch.php:119 src/Module/Contact/Match.php:122
msgid "No matches"
msgstr ""
#: src/Module/BaseSettings.php:80 #: src/Module/BaseSettings.php:80
msgid "Account" msgid "Account"
msgstr "" msgstr ""
@ -5981,6 +5973,21 @@ msgstr ""
msgid "The contact could not be added." msgid "The contact could not be added."
msgstr "" msgstr ""
#: src/Module/Contact/Match.php:77 src/Module/Profile/Attachment/Upload.php:80
#: src/Module/Profile/Attachment/Upload.php:102
#: src/Module/Profile/Photos/Upload.php:113
#: src/Module/Profile/Photos/Upload.php:162
msgid "Invalid request."
msgstr ""
#: src/Module/Contact/Match.php:84
msgid "No keywords to match. Please add keywords to your profile."
msgstr ""
#: src/Module/Contact/Match.php:127
msgid "Profile Match"
msgstr ""
#: src/Module/Contact/Profile.php:128 #: src/Module/Contact/Profile.php:128
msgid "Failed to update contact record." msgid "Failed to update contact record."
msgstr "" msgstr ""
@ -8108,13 +8115,6 @@ msgstr ""
msgid "Remove" msgid "Remove"
msgstr "" msgstr ""
#: src/Module/Profile/Attachment/Upload.php:80
#: src/Module/Profile/Attachment/Upload.php:102
#: src/Module/Profile/Photos/Upload.php:113
#: src/Module/Profile/Photos/Upload.php:162
msgid "Invalid request."
msgstr ""
#: src/Module/Profile/Attachment/Upload.php:117 #: src/Module/Profile/Attachment/Upload.php:117
msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" msgid "Sorry, maybe your upload is bigger than the PHP configuration allows"
msgstr "" msgstr ""

View File

@ -5,8 +5,8 @@
<form action="dirfind" method="get" /> <form action="dirfind" method="get" />
<input id="side-peoplefind-url" type="text" name="search" size="24" title="{{$nv.hint}}" /><input id="side-peoplefind-submit" type="submit" name="submit" value="{{$nv.findthem}}" /> <input id="side-peoplefind-url" type="text" name="search" size="24" title="{{$nv.hint}}" /><input id="side-peoplefind-submit" type="submit" name="submit" value="{{$nv.findthem}}" />
</form> </form>
<div class="side-link" id="side-match-link"><a href="match">{{$nv.similar}}</a></div> <div class="side-link" id="side-match-link"><a href="contact/match">{{$nv.similar}}</a></div>
<div class="side-link" id="side-suggest-link"><a href="suggest">{{$nv.suggest}}</a></div> <div class="side-link" id="side-suggest-link"><a href="contact/suggestions">{{$nv.suggest}}</a></div>
<div class="side-link" id="side-directory-link"><a href="directory">{{$nv.local_directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="directory">{{$nv.local_directory}}</a></div>
<div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink">{{$nv.directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink">{{$nv.directory}}</a></div>
<div class="side-link" id="side-random-profile-link"><a href="randprof" target="extlink">{{$nv.random}}</a></div> <div class="side-link" id="side-random-profile-link"><a href="randprof" target="extlink">{{$nv.random}}</a></div>

View File

@ -14,7 +14,7 @@
<div class="side-link" id="side-directory-link"><a href="directory">{{$nv.local_directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="directory">{{$nv.local_directory}}</a></div>
<div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink">{{$nv.directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink">{{$nv.directory}}</a></div>
{{* Additional links *}} {{* Additional links *}}
<div class="side-link" id="side-match-link"><a href="match">{{$nv.similar}}</a></div> <div class="side-link" id="side-match-link"><a href="contact/match">{{$nv.similar}}</a></div>
<div class="side-link" id="side-suggest-link"><a href="contact/suggestions">{{$nv.suggest}}</a></div> <div class="side-link" id="side-suggest-link"><a href="contact/suggestions">{{$nv.suggest}}</a></div>
<div class="side-link" id="side-random-profile-link"><a href="randprof" target="extlink">{{$nv.random}}</a></div> <div class="side-link" id="side-random-profile-link"><a href="randprof" target="extlink">{{$nv.random}}</a></div>