]> git.mxchange.org Git - friendica.git/commitdiff
Add new OStatus\PortableContacts module class
authorHypolite Petovan <hypolite@mrpetovan.com>
Fri, 11 Nov 2022 03:28:33 +0000 (22:28 -0500)
committerHypolite Petovan <hypolite@mrpetovan.com>
Mon, 14 Nov 2022 18:48:46 +0000 (13:48 -0500)
- Retain existing route /poco for backward compatibility
- Remove unsupported links to /poco/{nickname} route

src/Model/Contact.php
src/Module/Profile/Profile.php
src/Module/User/PortableContacts.php [new file with mode: 0644]
src/Module/Xrd.php
static/routes.config.php

index ee74cb1574bc313e0c5ab768c584f2fd380ece51..8239708e1c9e86707502e905841e92d3a53a952d 100644 (file)
@@ -729,7 +729,6 @@ class Contact
                        'notify'      => DI::baseUrl() . '/dfrn_notify/'  . $user['nickname'],
                        'poll'        => DI::baseUrl() . '/dfrn_poll/'    . $user['nickname'],
                        'confirm'     => DI::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
-                       'poco'        => DI::baseUrl() . '/poco/'         . $user['nickname'],
                        'name-date'   => DateTimeFormat::utcNow(),
                        'uri-date'    => DateTimeFormat::utcNow(),
                        'avatar-date' => DateTimeFormat::utcNow(),
@@ -811,7 +810,6 @@ class Contact
                        'notify'       => DI::baseUrl() . '/dfrn_notify/' . $user['nickname'],
                        'poll'         => DI::baseUrl() . '/dfrn_poll/'. $user['nickname'],
                        'confirm'      => DI::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
-                       'poco'         => DI::baseUrl() . '/poco/' . $user['nickname'],
                ];
 
 
index a6026609357d82d12a7d7f1fb939d8fa8c6f1e3d..07db082591df7149d20c325e052e07e6745adcba 100644 (file)
@@ -334,7 +334,6 @@ class Profile extends BaseProfile
                foreach ($dfrn_pages as $dfrn) {
                        $htmlhead .= '<link rel="dfrn-' . $dfrn . '" href="' . $baseUrl . '/dfrn_' . $dfrn . '/' . $nickname . '" />' . "\n";
                }
-               $htmlhead .= '<link rel="dfrn-poco" href="' . $baseUrl . '/poco/' . $nickname . '" />' . "\n";
 
                return $htmlhead;
        }
diff --git a/src/Module/User/PortableContacts.php b/src/Module/User/PortableContacts.php
new file mode 100644 (file)
index 0000000..6629994
--- /dev/null
@@ -0,0 +1,277 @@
+<?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/>.
+ *
+ * @see https://web.archive.org/web/20160405005550/http://portablecontacts.net/draft-spec.html
+ */
+
+namespace Friendica\Module\User;
+
+use Friendica\App;
+use Friendica\BaseModule;
+use Friendica\Content\Text\BBCode;
+use Friendica\Core\Cache\Capability\ICanCache;
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\L10n;
+use Friendica\Core\Protocol;
+use Friendica\Core\System;
+use Friendica\Database\Database;
+use Friendica\Module\Response;
+use Friendica\Network\HTTPException;
+use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Minimal implementation of the Portable Contacts protocol
+ * @see https://portablecontacts.github.io
+ */
+class PortableContacts extends BaseModule
+{
+       /** @var IManageConfigValues */
+       private $config;
+       /** @var Database */
+       private $database;
+       /** @var ICanCache */
+       private $cache;
+
+       public function __construct(ICanCache $cache, Database $database, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
+       {
+               parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+               $this->config   = $config;
+               $this->database = $database;
+               $this->cache    = $cache;
+       }
+
+       protected function rawContent(array $request = [])
+       {
+               if ($this->config->get('system', 'block_public') || $this->config->get('system', 'block_local_dir')) {
+                       throw new HTTPException\ForbiddenException();
+               }
+
+               $format = $request['format'] ?? 'json';
+               if ($format !== 'json') {
+                       throw new HTTPException\UnsupportedMediaTypeException();
+               }
+
+               $totalResults = $this->database->count('profile', ['net-publish' => true]);
+               if (!$totalResults) {
+                       throw new HTTPException\ForbiddenException();
+               }
+
+               if (!empty($request['startIndex']) && is_numeric($request['startIndex'])) {
+                       $startIndex = intval($request['startIndex']);
+               } else {
+                       $startIndex = 0;
+               }
+
+               $itemsPerPage = !empty($request['count']) && is_numeric($request['count']) ? intval($request['count']) : $totalResults;
+
+               $this->logger->info('Start system mode query');
+               $contacts = $this->database->selectToArray('owner-view', [], ['net-publish' => true], ['limit' => [$startIndex, $itemsPerPage]]);
+               $this->logger->info('Query done');
+
+               $return = [];
+               if (!empty($request['sorted'])) {
+                       $return['sorted'] = false;
+               }
+
+               if (!empty($request['filtered'])) {
+                       $return['filtered'] = false;
+               }
+
+               if (!empty($request['updatedSince'])) {
+                       $return['updatedSince'] = false;
+               }
+
+               $return['startIndex']   = $startIndex;
+               $return['itemsPerPage'] = $itemsPerPage;
+               $return['totalResults'] = $totalResults;
+
+               $return['entry'] = [];
+
+               $selectedFields = [
+                       'id'                => false,
+                       'displayName'       => false,
+                       'urls'              => false,
+                       'updated'           => false,
+                       'preferredUsername' => false,
+                       'photos'            => false,
+                       'aboutMe'           => false,
+                       'currentLocation'   => false,
+                       'network'           => false,
+                       'tags'              => false,
+                       'address'           => false,
+                       'contactType'       => false,
+                       'generation'        => false
+               ];
+
+               if (empty($request['fields']) || $request['fields'] == '@all') {
+                       foreach ($selectedFields as $k => $v) {
+                               $selectedFields[$k] = true;
+                       }
+               } else {
+                       $fields_req = explode(',', $request['fields']);
+                       foreach ($fields_req as $f) {
+                               $selectedFields[trim($f)] = true;
+                       }
+               }
+
+               if (!$contacts) {
+                       $return['entry'][] = [];
+               }
+
+               foreach ($contacts as $contact) {
+                       if (!isset($contact['updated'])) {
+                               $contact['updated'] = '';
+                       }
+
+                       if (!isset($contact['generation'])) {
+                               $contact['generation'] = 1;
+                       }
+
+                       if (empty($contact['keywords']) && isset($contact['pub_keywords'])) {
+                               $contact['keywords'] = $contact['pub_keywords'];
+                       }
+
+                       if (isset($contact['account-type'])) {
+                               $contact['contact-type'] = $contact['account-type'];
+                       }
+
+                       $cacheKey = 'about:' . $contact['nick'] . ':' . DateTimeFormat::utc($contact['updated'], DateTimeFormat::ATOM);
+                       $about    = $this->cache->get($cacheKey);
+                       if (is_null($about)) {
+                               $about = BBCode::convertForUriId($contact['uri-id'], $contact['about']);
+                               $this->cache->set($cacheKey, $about);
+                       }
+
+                       // Non connected persons can only see the keywords of a Diaspora account
+                       if ($contact['network'] == Protocol::DIASPORA) {
+                               $contact['location'] = '';
+                               $about               = '';
+                       }
+
+                       $entry = [];
+                       if ($selectedFields['id']) {
+                               $entry['id'] = (int)$contact['id'];
+                       }
+
+                       if ($selectedFields['displayName']) {
+                               $entry['displayName'] = $contact['name'];
+                       }
+
+                       if ($selectedFields['aboutMe']) {
+                               $entry['aboutMe'] = $about;
+                       }
+
+                       if ($selectedFields['currentLocation']) {
+                               $entry['currentLocation'] = $contact['location'];
+                       }
+
+                       if ($selectedFields['generation']) {
+                               $entry['generation'] = (int)$contact['generation'];
+                       }
+
+                       if ($selectedFields['urls']) {
+                               $entry['urls'] = [['value' => $contact['url'], 'type' => 'profile']];
+                               if ($contact['addr'] && ($contact['network'] !== Protocol::MAIL)) {
+                                       $entry['urls'][] = ['value' => 'acct:' . $contact['addr'], 'type' => 'webfinger'];
+                               }
+                       }
+
+                       if ($selectedFields['preferredUsername']) {
+                               $entry['preferredUsername'] = $contact['nick'];
+                       }
+
+                       if ($selectedFields['updated']) {
+                               $entry['updated'] = $contact['success_update'];
+
+                               if ($contact['name-date'] > $entry['updated']) {
+                                       $entry['updated'] = $contact['name-date'];
+                               }
+
+                               if ($contact['uri-date'] > $entry['updated']) {
+                                       $entry['updated'] = $contact['uri-date'];
+                               }
+
+                               if ($contact['avatar-date'] > $entry['updated']) {
+                                       $entry['updated'] = $contact['avatar-date'];
+                               }
+
+                               $entry['updated'] = date('c', strtotime($entry['updated']));
+                       }
+
+                       if ($selectedFields['photos']) {
+                               $entry['photos'] = [['value' => $contact['photo'], 'type' => 'profile']];
+                       }
+
+                       if ($selectedFields['network']) {
+                               $entry['network'] = $contact['network'];
+                               if ($entry['network'] == Protocol::STATUSNET) {
+                                       $entry['network'] = Protocol::OSTATUS;
+                               }
+
+                               if (($entry['network'] == '') && ($contact['self'])) {
+                                       $entry['network'] = Protocol::DFRN;
+                               }
+                       }
+
+                       if ($selectedFields['tags']) {
+                               $tags = str_replace(',', ' ', $contact['keywords']);
+                               $tags = explode(' ', $tags);
+
+                               $cleaned = [];
+                               foreach ($tags as $tag) {
+                                       $tag = trim(strtolower($tag));
+                                       if ($tag != '') {
+                                               $cleaned[] = $tag;
+                                       }
+                               }
+
+                               $entry['tags'] = [$cleaned];
+                       }
+
+                       if ($selectedFields['address']) {
+                               $entry['address'] = [];
+
+                               if (isset($contact['locality'])) {
+                                       $entry['address']['locality'] = $contact['locality'];
+                               }
+
+                               if (isset($contact['region'])) {
+                                       $entry['address']['region'] = $contact['region'];
+                               }
+
+                               if (isset($contact['country'])) {
+                                       $entry['address']['country'] = $contact['country'];
+                               }
+                       }
+
+                       if ($selectedFields['contactType']) {
+                               $entry['contactType'] = intval($contact['contact-type']);
+                       }
+
+                       $return['entry'][] = $entry;
+               }
+
+               $this->logger->info('End of poco');
+
+               System::jsonExit($return);
+       }
+}
index 4e4603fbdb20dcc3848a7d8bc6d98603d9b41eb6..29641482f625b86a41a1a7050a6fcb98e89c9c58 100644 (file)
@@ -184,10 +184,6 @@ class Xrd extends BaseModule
                                        'type' => 'text/html',
                                        'href' => $baseURL . '/hcard/' . $owner['nickname'],
                                ],
-                               [
-                                       'rel'  => ActivityNamespace::POCO,
-                                       'href' => $owner['poco'],
-                               ],
                                [
                                        'rel'  => 'http://webfinger.net/rel/avatar',
                                        'type' => $avatar['type'],
@@ -272,56 +268,50 @@ class Xrd extends BaseModule
                                        ]
                                ],
                                '5:link' => [
-                                       '@attributes' => [
-                                               'rel'  => 'http://portablecontacts.net/spec/1.0',
-                                               'href' => $owner['poco']
-                                       ]
-                               ],
-                               '6:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://webfinger.net/rel/avatar',
                                                'type' => $avatar['type'],
                                                'href' => User::getAvatarUrl($owner)
                                        ]
                                ],
-                               '7:link' => [
+                               '6:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://joindiaspora.com/seed_location',
                                                'type' => 'text/html',
                                                'href' => $baseURL
                                        ]
                                ],
-                               '8:link' => [
+                               '7:link' => [
                                        '@attributes' => [
                                                'rel'  => 'salmon',
                                                'href' => $baseURL . '/salmon/' . $owner['nickname']
                                        ]
                                ],
-                               '9:link' => [
+                               '8:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://salmon-protocol.org/ns/salmon-replies',
                                                'href' => $baseURL . '/salmon/' . $owner['nickname']
                                        ]
                                ],
-                               '10:link' => [
+                               '9:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://salmon-protocol.org/ns/salmon-mention',
                                                'href' => $baseURL . '/salmon/' . $owner['nickname'] . '/mention'
                                        ]
                                ],
-                               '11:link' => [
+                               '10:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://ostatus.org/schema/1.0/subscribe',
                                                'template' => $baseURL . '/contact/follow?url={uri}'
                                        ]
                                ],
-                               '12:link' => [
+                               '11:link' => [
                                        '@attributes' => [
                                                'rel'  => 'magic-public-key',
                                                'href' => 'data:application/magic-public-key,' . Salmon::salmonKey($owner['spubkey'])
                                        ]
                                ],
-                               '13:link' => [
+                               '12:link' => [
                                        '@attributes' => [
                                                'rel'  => 'http://purl.org/openwebauth/v1',
                                                'type' => 'application/x-zot+json',
index 0e9ce965e261e8ef83090ef6aa56191cc8dda4b6..927b018403cf3605479826b1a05ec3efae0bb68b 100644 (file)
@@ -569,9 +569,10 @@ return [
                '/{sub1}/{sub2}/{url}' => [Module\Proxy::class, [R::GET]],
        ],
 
-       '/pubsub/{nickname}/{cid:\d+}' => [Module\OStatus\PubSub::class,       [R::GET, R::POST]],
-       '/pubsubhubbub/{nickname}'     => [Module\OStatus\PubSubHubBub::class, [        R::POST]],
-       '/salmon/{nickname}'           => [Module\OStatus\Salmon::class,       [        R::POST]],
+       '/poco'                        => [Module\User\PortableContacts::class,    [R::GET         ]],
+       '/pubsub/{nickname}/{cid:\d+}' => [Module\OStatus\PubSub::class,           [R::GET, R::POST]],
+       '/pubsubhubbub/{nickname}'     => [Module\OStatus\PubSubHubBub::class,     [        R::POST]],
+       '/salmon/{nickname}'           => [Module\OStatus\Salmon::class,           [        R::POST]],
 
        '/search' => [
                '[/]'                  => [Module\Search\Index::class, [R::GET         ]],