From e4bdb21a540c668fa7bf53897e92aa994229e85c Mon Sep 17 00:00:00 2001 From: Diogo Cordeiro Date: Mon, 12 Aug 2019 04:45:25 +0100 Subject: [PATCH] [NodeInfo] New endpoint and formula for computing active users Seriously improved documentation Now NodeInfo 2.0 is available at /api/nodeinfo/2.0.json For active users we now also consider favourites and recently created accounts Some further minor bug fixes and full review of the implementation --- lib/util.php | 4 +- plugins/Nodeinfo/NodeinfoPlugin.php | 116 +++++-- plugins/Nodeinfo/README.md | 7 +- plugins/Nodeinfo/actions/nodeinfo_2_0.php | 384 +++++++++++++++++----- plugins/Nodeinfo/actions/nodeinfojrd.php | 33 +- plugins/Nodeinfo/classes/Usage_stats.php | 91 +++-- plugins/Nodeinfo/scripts/fix_stats.php | 63 ++-- 7 files changed, 519 insertions(+), 179 deletions(-) diff --git a/lib/util.php b/lib/util.php index 966c415024..704dd0bf4c 100644 --- a/lib/util.php +++ b/lib/util.php @@ -2657,7 +2657,7 @@ function common_strip_html($html, $trim=true, $save_whitespace=false) * @param string|bool $size * @return int the php.ini upload limit in machine-readable format */ -function _common_size_str_to_int($size) : int +function _common_size_str_to_int($size): int { // `memory_limit` can be -1 and `post_max_size` can be 0 // for unlimited. Consistency. @@ -2692,7 +2692,7 @@ function _common_size_str_to_int($size) : int * * @return int */ -function common_get_preferred_php_upload_limit() : int { +function common_get_preferred_php_upload_limit(): int { return min(_common_size_str_to_int(ini_get('post_max_size')), _common_size_str_to_int(ini_get('upload_max_filesize')), _common_size_str_to_int(ini_get('memory_limit'))); diff --git a/plugins/Nodeinfo/NodeinfoPlugin.php b/plugins/Nodeinfo/NodeinfoPlugin.php index 3417603c99..6a3d4e84b3 100644 --- a/plugins/Nodeinfo/NodeinfoPlugin.php +++ b/plugins/Nodeinfo/NodeinfoPlugin.php @@ -1,20 +1,52 @@ . -if (!defined('GNUSOCIAL')) { - exit(1); -} +/** + * Plugin that presents basic instance information using the [NodeInfo standard](http://nodeinfo.diaspora.software/). + * + * @package NodeInfo + * @author Stéphane Bérubé + * @author Diogo Cordeiro + * @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(); + +/** + * Controls cache and routes + * + * @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 NodeinfoPlugin extends Plugin { - const PLUGIN_VERSION = '1.0.2'; + const PLUGIN_VERSION = '2.0.0'; - public function onRouterInitialized($m) + public function onRouterInitialized($m): bool { - $m->connect('.well-known/nodeinfo', - ['action' => 'nodeinfojrd']); + $m->connect( + '.well-known/nodeinfo', + ['action' => 'nodeinfojrd'] + ); - $m->connect('main/nodeinfo/2.0', - ['action' => 'nodeinfo_2_0']); + $m->connect( + 'api/nodeinfo/2.0.json', + ['action' => 'nodeinfo_2_0'] + ); return true; } @@ -22,9 +54,10 @@ class NodeinfoPlugin extends Plugin /** * Make sure necessary tables are filled out. * - * @return boolean hook true + * @return bool hook true + * @author Diogo Cordeiro */ - public function onCheckSchema() + public function onCheckSchema(): bool { // Ensure schema $schema = Schema::get(); @@ -55,10 +88,11 @@ class NodeinfoPlugin extends Plugin /** * Increment notices/replies counter * - * @return boolean hook flag + * @param Notice $notice + * @return bool hook flag * @author Diogo Cordeiro */ - public function onStartNoticeDistribute($notice) + public function onStartNoticeDistribute(Notice $notice): bool { assert($notice->id > 0); // Ignore if not a valid notice @@ -68,16 +102,18 @@ class NodeinfoPlugin extends Plugin return true; } - // Ignore for activity/non-post-verb notices + // Ignore for activity/non-(post/share)-verb notices if (method_exists('ActivityUtils', 'compareVerbs')) { - $is_post_verb = ActivityUtils::compareVerbs( + $is_valid_verb = ActivityUtils::compareVerbs( $notice->verb, - [ActivityVerb::POST] + [ActivityVerb::POST, + ActivityVerb::SHARE] ); } else { - $is_post_verb = ($notice->verb == ActivityVerb::POST ? true : false); + $is_valid_verb = ($notice->verb == ActivityVerb::POST || + $notice->verb == ActivityVerb::SHARE); } - if ($notice->source == 'activity' || !$is_post_verb) { + if ($notice->source == 'activity' || !$is_valid_verb) { return true; } @@ -105,10 +141,13 @@ class NodeinfoPlugin extends Plugin /** * Decrement notices/replies counter * - * @return boolean hook flag + * @param User $user + * @param Notice $notice + * @return bool hook flag + * @throws UserNoProfileException * @author Diogo Cordeiro */ - public function onStartDeleteOwnNotice($user, $notice) + public function onStartDeleteOwnNotice(User $user, Notice $notice): bool { $profile = $user->getProfile(); @@ -133,10 +172,10 @@ class NodeinfoPlugin extends Plugin /** * Increment users counter * - * @return boolean hook flag + * @return bool hook flag * @author Diogo Cordeiro */ - public function onEndRegistrationTry() + public function onEndRegistrationTry(): bool { $us = Usage_stats::getKV('type', 'users'); $us->count += 1; @@ -147,10 +186,10 @@ class NodeinfoPlugin extends Plugin /** * Decrement users counter * - * @return boolean hook flag + * @return bool hook flag * @author Diogo Cordeiro */ - public function onEndDeleteUser() + public function onEndDeleteUser(): bool { $us = Usage_stats::getKV('type', 'users'); $us->count -= 1; @@ -158,23 +197,38 @@ class NodeinfoPlugin extends Plugin return true; } - - public function onPluginVersion(array &$versions) + /** + * Plugin version information + * + * @param array $versions + * @return bool hook true + * @throws Exception + */ + public function onPluginVersion(array &$versions): bool { - $versions[] = ['name' => 'Nodeinfo', + $versions[] = [ + 'name' => 'Nodeinfo', 'version' => self::PLUGIN_VERSION, - 'author' => 'chimo', - 'homepage' => 'https://github.com/chimo/gs-nodeinfo', - 'description' => _m('Plugin that presents basic instance information using the NodeInfo standard.')]; + 'author' => 'Stéphane Bérubé, Diogo Cordeiro', + 'homepage' => 'https://code.chromic.org/chimo/gs-nodeinfo', + 'description' => _m('Plugin that presents basic instance information using the NodeInfo standard.') + ]; return true; } - public function onEndUpgrade() + /** + * Cache was added in a newer version of the plugin, this ensures we fix cached values on upgrade + * + * @return bool hook flag + * @author Diogo Cordeiro + */ + public function onEndUpgrade(): bool { $users = new Usage_stats(); if ($users->getUserCount() == 0) { define('NODEINFO_UPGRADE', true); require_once __DIR__ . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'fix_stats.php'; } + return true; } } diff --git a/plugins/Nodeinfo/README.md b/plugins/Nodeinfo/README.md index 872e201470..78f976c560 100644 --- a/plugins/Nodeinfo/README.md +++ b/plugins/Nodeinfo/README.md @@ -1,7 +1,8 @@ -# Nodeinfo plugin for GNU social +# Nodeinfo support for GNU social Plugin that presents basic instance information using the [NodeInfo standard](http://nodeinfo.diaspora.software/). -At the moment, the information is presented at the "/main/nodeinfo/2.0" endpoint. +The information is presented at the "/nodeinfo/2.0.json" endpoint. -Other tools can then scrape that information and present it in various ways. For example: [https://fediverse.network/](https://fediverse.network/) +Other tools can then scrape that information and present it in various ways. +For example: [https://fediverse.network/](https://fediverse.network/) diff --git a/plugins/Nodeinfo/actions/nodeinfo_2_0.php b/plugins/Nodeinfo/actions/nodeinfo_2_0.php index 63f59e11e4..2150bfb5e8 100644 --- a/plugins/Nodeinfo/actions/nodeinfo_2_0.php +++ b/plugins/Nodeinfo/actions/nodeinfo_2_0.php @@ -1,43 +1,78 @@ . -if (!defined('GNUSOCIAL')) { - exit(1); -} +/** + * The information is presented at the "api/nodeinfo/2.0.json" endpoint. + * + * @package NodeInfo + * @author Stéphane Bérubé + * @author Diogo Cordeiro + * @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 ApiAction +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() + protected function handle(): void { parent::handle(); - + header('Access-Control-Allow-Origin: *'); $this->plugins = $this->getActivePluginList(); - $this->showNodeInfo(); } - public function getActivePluginList() + /** + * Most functionality depends on the active plugins, this gives us enough information concerning that + * + * @return array + * @author Stéphane Bérubé + * @author Diogo Cordeiro + */ + public function getActivePluginList(): array { - $pluginversions = array(); - $plugins = array(); + $plugin_version = []; + $plugins = []; - Event::handle('PluginVersion', array(&$pluginversions)); + Event::handle('PluginVersion', [&$plugin_version]); - foreach ($pluginversions as $plugin) { - $plugins[strtolower($plugin['name'])] = 1; + foreach ($plugin_version as $plugin) { + $plugins[str_replace(' ', '', strtolower($plugin['name']))] = true; } return $plugins; } - /* - * Technically, the NodeInfo spec defines 'active' as 'signed in at least once', - * but GNU social doesn't keep track of when users last logged in, so let's return - * the number of users that 'posted at least once', I guess. + /** + * The NodeInfo page + * + * @return void + * @author Stéphane Bérubé + * @author Diogo Cordeiro */ - - public function showNodeInfo() + public function showNodeInfo(): void { $openRegistrations = $this->getRegistrationsStatus(); $userCount = $this->getUserCount(); @@ -51,43 +86,208 @@ class Nodeinfo_2_0Action extends ApiAction $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', - 'version' => GNUSOCIAL_VERSION + '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, - // TODO: Have plugins register services + // 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 ], - 'metadata' => new stdClass() + // Free form key value pairs for software specific values. Clients should not rely on any specific key present. + 'metadata' => $metadata ]); - $this->initDocument('json'); + header('Content-Type: application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8'); print $json; - $this->endDocument('json'); } - public function getRegistrationsStatus() + /** + * 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 + */ + 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 + * @author Stéphane Bérubé + */ + 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 + * @author Stéphane Bérubé + */ + 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é + */ + public function getRegistrationsStatus(): bool { $areRegistrationsClosed = (common_config('site', 'closed')) ? true : false; $isSiteInviteOnly = (common_config('site', 'inviteonly')) ? true : false; @@ -95,7 +295,13 @@ class Nodeinfo_2_0Action extends ApiAction return !($areRegistrationsClosed || $isSiteInviteOnly); } - public function getUserCount() + /** + * The total amount of on this server registered users. + * + * @return int + * @author Stéphane Bérubé + */ + public function getUserCount(): int { $users = new Usage_stats(); $userCount = $users->getUserCount(); @@ -103,7 +309,46 @@ class Nodeinfo_2_0Action extends ApiAction return $userCount; } - public function getPostCount() + /** + * 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 + */ + public function getActiveUsers(int $days): int + { + $query = " + SELECT COUNT(DISTINCT profile_id) as active_users_count + FROM ( + SELECT profile_id FROM notice WHERE notice.created >= NOW() - INTERVAL {$days} DAY AND notice.is_local = 1 + UNION ALL + SELECT user_id FROM fave INNER JOIN user ON fave.user_id = user.id WHERE fave.created >= NOW() - INTERVAL {$days} DAY + UNION ALL + SELECT id FROM user WHERE user.created >= NOW() - INTERVAL {$days} DAY + ) as source"; + + $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é + */ + public function getPostCount(): int { $posts = new Usage_stats(); $postCount = $posts->getPostCount(); @@ -111,7 +356,13 @@ class Nodeinfo_2_0Action extends ApiAction return $postCount; } - public function getCommentCount() + /** + * The amount of comments that were made by users that are registered on this server. + * + * @return int + * @author Stéphane Bérubé + */ + public function getCommentCount(): int { $comments = new Usage_stats(); $commentCount = $comments->getCommentCount(); @@ -119,61 +370,32 @@ class Nodeinfo_2_0Action extends ApiAction return $commentCount; } - public function getActiveUsers($days) + /** + * Some additional information related to this GNU social instance + * + * @return array + * @author Diogo Cordeiro + */ + public function getMetadata(): array { - $notices = new Notice(); - $notices->joinAdd(array('profile_id', 'user:id')); - $notices->whereAdd('notice.created >= NOW() - INTERVAL ' . $days . ' DAY'); + $metadata = [ + 'nodeName' => common_config('site', 'name'), + 'software' => [ + 'homepage' => 'https://gnu.social/', + 'repository' => 'https://notabug.org/diogo/gnu-social', + ], + 'uploadLimit' => common_get_preferred_php_upload_limit(), + 'postFormats' => [ + 'text/plain', + 'text/html' + ], + 'features' => [] + ]; - $activeUsersCount = $notices->count('distinct profile_id'); - - return $activeUsersCount; - } - - public function getProtocols() - { - $protocols = []; - - Event::handle('NodeInfoProtocols', array(&$protocols)); - - return $protocols; - } - - public function getInboundServices() - { - // FIXME: Are those always on? - $inboundServices = array('atom1.0', 'rss2.0'); - - if (array_key_exists('twitterbridge', $this->plugins) && common_config('twitterimport', 'enabled')) { - $inboundServices[] = 'twitter'; + if (array_key_exists('poll', $this->plugins)) { + $metadata['features'][] = 'polls'; } - if (array_key_exists('ostatus', $this->plugins)) { - $inboundServices[] = 'gnusocial'; - } - - return $inboundServices; - } - - public function getOutboundServices() - { - $xmppEnabled = (array_key_exists('xmpp', $this->plugins) && common_config('xmpp', 'enabled')) ? true : false; - - // FIXME: Are those always on? - $outboundServices = array('atom1.0', 'rss2.0'); - - if (array_key_exists('twitterbridge', $this->plugins)) { - $outboundServices[] = 'twitter'; - } - - if (array_key_exists('ostatus', $this->plugins)) { - $outboundServices[] = 'gnusocial'; - } - - if ($xmppEnabled) { - $outboundServices[] = 'xmpp'; - } - - return $outboundServices; + return $metadata; } } diff --git a/plugins/Nodeinfo/actions/nodeinfojrd.php b/plugins/Nodeinfo/actions/nodeinfojrd.php index d7a2829144..4efb3302ac 100644 --- a/plugins/Nodeinfo/actions/nodeinfojrd.php +++ b/plugins/Nodeinfo/actions/nodeinfojrd.php @@ -1,9 +1,36 @@ . -if (!defined('GNUSOCIAL')) { - exit(1); -} +/** + * Provided in /.well-known/nodeinfo + * + * @package NodeInfo + * @author Stéphane Bérubé + * @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(); + +/** + * JRD document for NodeInfo + * + * @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 NodeinfoJRDAction extends XrdAction { const NODEINFO_2_0_REL = 'http://nodeinfo.diaspora.software/ns/schema/2.0'; diff --git a/plugins/Nodeinfo/classes/Usage_stats.php b/plugins/Nodeinfo/classes/Usage_stats.php index 48148b015c..64cc64934b 100644 --- a/plugins/Nodeinfo/classes/Usage_stats.php +++ b/plugins/Nodeinfo/classes/Usage_stats.php @@ -1,72 +1,91 @@ . + /** - * GNU social - a federating social network + * Table for storing Nodeinfo statistics * - * LICENCE: 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 . + * @package NodeInfo + * @author Diogo Cordeiro + * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ -if (!defined('GNUSOCIAL')) { - exit(1); -} +defined('GNUSOCIAL') || die(); /** - * Table Definition for Usage_stats + * Table Definition for usage_stats and some getters + * + * @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 Usage_stats extends Managed_DataObject { - ###START_AUTOCODE - /* the code below is auto generated do not remove the above tag */ - public $__table = 'usage_stats'; // table name public $type; // varchar(191) unique_key not 255 because utf8mb4 takes more space public $count; // int(4) - public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + public $modified; // datetime() not_null default_CURRENT_TIMESTAMP - /* the code above is auto generated do not remove the tag below */ - ###END_AUTOCODE - - public static function schemaDef() + /** + * Table Definition for usage_stats + * + * @return array + */ + public static function schemaDef(): array { return [ 'description' => 'node stats', 'fields' => [ - 'type' => ['type' => 'varchar', 'length' => 191, 'description' => 'Type of countable entity'], + 'type' => ['type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'Type of countable entity'], 'count' => ['type' => 'int', 'size' => 'int', 'default' => 0, 'description' => 'Number of entities of this type'], - 'modified' => ['type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'], + 'modified' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], ], 'primary key' => ['type'], - 'unique keys' => [ - 'usage_stats_key' => ['type'], - ], 'indexes' => [ 'user_stats_idx' => ['type'], ], ]; } - public function getUserCount() + /** + * Total number of users + * + * @return int + */ + public function getUserCount(): int { - return intval(Usage_stats::getKV('type', 'users')->count); + return Usage_stats::getKV('type', 'users')->count; } - public function getPostCount() + /** + * Total number of dents + * + * @return int + */ + public function getPostCount(): int { - return intval(Usage_stats::getKV('type', 'posts')->count); + return Usage_stats::getKV('type', 'posts')->count; } - public function getCommentCount() + /** + * Total number of replies + * + * @return int + */ + public function getCommentCount(): int { - return intval(Usage_stats::getKV('type', 'comments')->count); + return Usage_stats::getKV('type', 'comments')->count; } } diff --git a/plugins/Nodeinfo/scripts/fix_stats.php b/plugins/Nodeinfo/scripts/fix_stats.php index a34e24f827..7876442da6 100755 --- a/plugins/Nodeinfo/scripts/fix_stats.php +++ b/plugins/Nodeinfo/scripts/fix_stats.php @@ -1,32 +1,32 @@ #!/usr/bin/env php . + /** - * GNU social - a federating social network + * Fix Nodeinfo statistics * - * LICENCE: 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 . - * - * @category Plugin - * @package GNUsocial - * @copyright 2018 Free Software Foundation http://fsf.org - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link https://www.gnu.org/software/social/ + * @package NodeInfo + * @author Diogo Cordeiro + * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ -define('INSTALLDIR', realpath(__DIR__ . '/../../..')); +define('INSTALLDIR', dirname(dirname(dirname(__DIR__)))); if (!defined('NODEINFO_UPGRADE')) { - $longoptions = ['type=']; $helptext = << + */ +function getUserCount(): int { $users = new User(); $userCount = $users->count(); @@ -103,6 +108,12 @@ function getUserCount() return $userCount; } +/** + * Total number of dents + * + * @return int + * @author Stéphane Bérubé + */ function getPostCount() { $notices = new Notice(); @@ -113,6 +124,12 @@ function getPostCount() return $noticeCount; } +/** + * Total number of replies + * + * @return int + * @author Stéphane Bérubé + */ function getCommentCount() { $notices = new Notice();