123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- <?php
- // This file is part of GNU social - https://www.gnu.org/software/social
- //
- // GNU social 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.
- //
- // GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
- /**
- * The information is presented at the "api/nodeinfo/2.0.json" endpoint.
- *
- * @package NodeInfo
- * @author Stéphane Bérubé <chimo@chromic.org>
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
- * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
- */
- defined('GNUSOCIAL') || die();
- /**
- * NodeInfo 2.0
- *
- * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
- * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
- */
- class Nodeinfo_2_0Action extends Action
- {
- private $plugins;
- protected function handle(): void
- {
- parent::handle();
- header('Access-Control-Allow-Origin: *');
- $this->plugins = $this->getActivePluginList();
- $this->showNodeInfo();
- }
- /**
- * Most functionality depends on the active plugins, this gives us enough information concerning that
- *
- * @return array
- * @author Stéphane Bérubé <chimo@chromic.org>
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- */
- public function getActivePluginList(): array
- {
- $plugin_version = [];
- $plugins = [];
- Event::handle('PluginVersion', [&$plugin_version]);
- foreach ($plugin_version as $plugin) {
- $plugins[str_replace(' ', '', strtolower($plugin['name']))] = true;
- }
- return $plugins;
- }
- /**
- * The NodeInfo page
- *
- * @return void
- * @author Stéphane Bérubé <chimo@chromic.org>
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- */
- public function showNodeInfo(): void
- {
- $openRegistrations = $this->getRegistrationsStatus();
- $userCount = $this->getUserCount();
- $postCount = $this->getPostCount();
- $commentCount = $this->getCommentCount();
- $usersActiveHalfyear = $this->getActiveUsers(180);
- $usersActiveMonth = $this->getActiveUsers(30);
- $protocols = $this->getProtocols();
- $inboundServices = $this->getInboundServices();
- $outboundServices = $this->getOutboundServices();
- $metadata = $this->getMetadata();
- /* Required NodeInfo fields
- "version",
- "software",
- "protocols",
- "services",
- "openRegistrations",
- "usage",
- "metadata"
- */
- $json = json_encode([
- // The schema version, must be 2.0.
- 'version' => '2.0',
- // [Mandatory] Metadata about server software in use.
- 'software' => [
- 'name' => 'gnusocial', // The canonical name of this server software.
- 'version' => GNUSOCIAL_VERSION // The version of this server software.
- ],
- // The protocols supported on this server.
- // The spec requires an array containing at least 1 item but we can't ensure that.
- 'protocols' => $protocols,
- // The third party sites this server can connect to via their application API.
- 'services' => [
- // The third party sites this server can retrieve messages from for combined display with regular traffic.
- 'inbound' => $inboundServices,
- // The third party sites this server can publish messages to on the behalf of a user.
- 'outbound' => $outboundServices
- ],
- // Whether this server allows open self-registration.
- 'openRegistrations' => $openRegistrations,
- // Usage statistics for this server.
- 'usage' => [
- 'users' => [
- // The total amount of on this server registered users.
- 'total' => $userCount,
- // The amount of users that signed in at least once in the last 180 days.
- 'activeHalfyear' => $usersActiveHalfyear,
- // The amount of users that signed in at least once in the last 30 days.
- 'activeMonth' => $usersActiveMonth
- ],
- // The amount of posts that were made by users that are registered on this server.
- 'localPosts' => $postCount,
- // The amount of comments that were made by users that are registered on this server.
- 'localComments' => $commentCount
- ],
- // Free form key value pairs for software specific values. Clients should not rely on any specific key present.
- 'metadata' => $metadata
- ]);
- header('Content-Type: application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8');
- print $json;
- }
- /**
- * The protocols supported on this server.
- * The spec requires an array containing at least 1 item but we can't ensure that
- *
- * These can only be one of:
- * - activitypub,
- * - buddycloud,
- * - dfrn,
- * - diaspora,
- * - libertree,
- * - ostatus,
- * - pumpio,
- * - tent,
- * - xmpp,
- * - zot
- *
- * @return array
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- */
- public function getProtocols(): array
- {
- $protocols = [];
- Event::handle('NodeInfoProtocols', [&$protocols]);
- return $protocols;
- }
- /**
- * The third party sites this server can retrieve messages from for combined display with regular traffic.
- *
- * These can only be one of:
- * - atom1.0,
- * - gnusocial,
- * - imap,
- * - pnut,
- * - pop3,
- * - pumpio,
- * - rss2.0,
- * - twitter
- *
- * @return array
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getInboundServices(): array
- {
- $inboundServices = [];
- $ostatusEnabled = array_key_exists('ostatus', $this->plugins);
- // We need those two to read feeds (despite WebSub).
- if ($ostatusEnabled && array_key_exists('feedpoller', $this->plugins)) {
- $inboundServices[] = 'atom1.0';
- $inboundServices[] = 'rss2.0';
- }
- if (array_key_exists('twitterbridge', $this->plugins) && common_config('twitterimport', 'enabled')) {
- $inboundServices[] = 'twitter';
- }
- if (array_key_exists('imap', $this->plugins)) {
- $inboundServices[] = 'imap';
- }
- // We can receive messages from another GNU social instance if we have at least one of those enabled.
- // And the same happens in the other instance
- if ($ostatusEnabled || array_key_exists('activitypub', $this->plugins)) {
- $inboundServices[] = 'gnusocial';
- }
- return $inboundServices;
- }
- /**
- * The third party sites this server can publish messages to on the behalf of a user.
- *
- * These can only be one of:
- * - atom1.0,
- * - blogger,
- * - buddycloud,
- * - diaspora,
- * - dreamwidth,
- * - drupal,
- * - facebook,
- * - friendica,
- * - gnusocial,
- * - google,
- * - insanejournal,
- * - libertree,
- * - linkedin,
- * - livejournal,
- * - mediagoblin,
- * - myspace,
- * - pinterest,
- * - pnut,
- * - posterous,
- * - pumpio,
- * - redmatrix,
- * - rss2.0,
- * - smtp,
- * - tent,
- * - tumblr,
- * - twitter,
- * - wordpress,
- * - xmpp
- *
- * @return array
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getOutboundServices(): array
- {
- // Those two are always available
- $outboundServices = ['atom1.0', 'rss2.0'];
- if (array_key_exists('twitterbridge', $this->plugins)) {
- $outboundServices[] = 'twitter';
- }
- // We can send messages to another GNU social instance if we have at least one of those enabled.
- // And the same happens in the other instance
- if (array_key_exists('ostatus', $this->plugins) ||
- array_key_exists('activitypub', $this->plugins)) {
- $outboundServices[] = 'gnusocial';
- }
- $xmppEnabled = (array_key_exists('xmpp', $this->plugins) && common_config('xmpp', 'enabled')) ? true : false;
- if ($xmppEnabled) {
- $outboundServices[] = 'xmpp';
- }
- return $outboundServices;
- }
- /**
- * Whether this server allows open self-registration.
- *
- * @return bool
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getRegistrationsStatus(): bool
- {
- $areRegistrationsClosed = (common_config('site', 'closed')) ? true : false;
- $isSiteInviteOnly = (common_config('site', 'inviteonly')) ? true : false;
- return !($areRegistrationsClosed || $isSiteInviteOnly);
- }
- /**
- * The total amount of on this server registered users.
- *
- * @return int
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getUserCount(): int
- {
- $users = new Usage_stats();
- $userCount = $users->getUserCount();
- return $userCount;
- }
- /**
- * The amount of users that were active at least once in the last $days days.
- *
- * Technically, the NodeInfo spec defines 'active' as 'signed in at least once in the
- * last {180, 30} days depending on request', but GNU social doesn't keep track of when
- * users last logged in.
- *
- * Therefore, we use Favourites, Notices and Date of account creation to underestimate a
- * value. Underestimate because a user that only logs in to see his feed is too an active
- * user.
- *
- * @param int $days
- * @return int
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- */
- public function getActiveUsers(int $days): int
- {
- $userTable = common_database_tablename('user');
- $query = <<<END
- SELECT COUNT(DISTINCT profile_id) AS active_users_count
- FROM (
- SELECT profile_id FROM notice
- WHERE notice.created >= CURRENT_DATE - INTERVAL '{$days}' DAY AND notice.is_local = 1
- UNION ALL
- SELECT user_id FROM fave INNER JOIN {$userTable} ON fave.user_id = {$userTable}.id
- WHERE fave.created >= CURRENT_DATE - INTERVAL '{$days}' DAY
- UNION ALL
- SELECT id FROM {$userTable} WHERE {$userTable}.created >= CURRENT_DATE - INTERVAL '{$days}' DAY
- ) AS source
- LEFT JOIN profile_role USING (profile_id)
- WHERE profile_role.profile_id IS NULL OR profile_role.role <> 'silenced';
- END;
- $activeUsersCount = new DB_DataObject();
- $activeUsersCount->query($query);
- $activeUsersCount->fetch();
- return $activeUsersCount->active_users_count;
- }
- /**
- * The amount of posts that were made by users that are registered on this server.
- *
- * @return int
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getPostCount(): int
- {
- $posts = new Usage_stats();
- $postCount = $posts->getPostCount();
- return $postCount;
- }
- /**
- * The amount of comments that were made by users that are registered on this server.
- *
- * @return int
- * @author Stéphane Bérubé <chimo@chromic.org>
- */
- public function getCommentCount(): int
- {
- $comments = new Usage_stats();
- $commentCount = $comments->getCommentCount();
- return $commentCount;
- }
- /**
- * Some additional information related to this GNU social instance
- *
- * @return array
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- */
- public function getMetadata(): array
- {
- $metadata = [
- 'nodeName' => common_config('site', 'name'),
- 'software' => [
- 'homepage' => GNUSOCIAL_ENGINE_URL,
- 'repository' => GNUSOCIAL_ENGINE_REPO_URL,
- ],
- 'uploadLimit' => common_get_preferred_php_upload_limit(),
- 'postFormats' => [
- 'text/plain',
- 'text/html'
- ],
- 'features' => []
- ];
- if (array_key_exists('poll', $this->plugins)) {
- $metadata['features'][] = 'polls';
- }
- return $metadata;
- }
- }
|