diff --git a/mod/_well_known.php b/mod/_well_known.php index f6a351bb2..a5e167de2 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -3,6 +3,7 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\System; +use Friendica\Module\Nodeinfo; require_once 'mod/hostxrd.php'; require_once 'mod/nodeinfo.php'; @@ -19,7 +20,7 @@ function _well_known_init(App $a) wk_social_relay(); break; case "nodeinfo": - nodeinfo_wellknown($a); + Nodeinfo::printWellKnown($a); break; case "webfinger": xrd_init($a); diff --git a/mod/nodeinfo.php b/mod/nodeinfo.php deleted file mode 100644 index da9dbb87c..000000000 --- a/mod/nodeinfo.php +++ /dev/null @@ -1,221 +0,0 @@ - [['rel' => 'http://nodeinfo.diaspora.software/ns/schema/1.0', - 'href' => System::baseUrl().'/nodeinfo/1.0']]]; - - header('Content-type: application/json; charset=utf-8'); - echo json_encode($nodeinfo, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); - exit; -} - -function nodeinfo_init(App $a) { - if (!Config::get('system', 'nodeinfo')) { - System::httpExit(404); - } - - if (($a->argc != 2) || ($a->argv[1] != '1.0')) { - System::httpExit(404); - } - - $smtp = (function_exists('imap_open') && !Config::get('system', 'imap_disabled') && !Config::get('system', 'dfrn_only')); - - $nodeinfo = []; - $nodeinfo['version'] = '1.0'; - $nodeinfo['software'] = ['name' => 'friendica', 'version' => FRIENDICA_VERSION.'-'.DB_UPDATE_VERSION]; - - $nodeinfo['protocols'] = []; - $nodeinfo['protocols']['inbound'] = []; - $nodeinfo['protocols']['outbound'] = []; - - if (Config::get('system', 'diaspora_enabled')) { - $nodeinfo['protocols']['inbound'][] = 'diaspora'; - $nodeinfo['protocols']['outbound'][] = 'diaspora'; - } - - $nodeinfo['protocols']['inbound'][] = 'friendica'; - $nodeinfo['protocols']['outbound'][] = 'friendica'; - - if (!Config::get('system', 'ostatus_disabled')) { - $nodeinfo['protocols']['inbound'][] = 'gnusocial'; - $nodeinfo['protocols']['outbound'][] = 'gnusocial'; - } - - $nodeinfo['services'] = []; - $nodeinfo['services']['inbound'] = []; - $nodeinfo['services']['outbound'] = []; - - $nodeinfo['usage'] = []; - - $nodeinfo['openRegistrations'] = intval(Config::get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED; - - $nodeinfo['metadata'] = ['nodeName' => Config::get('config', 'sitename')]; - - if (Config::get('system', 'nodeinfo')) { - - $nodeinfo['usage']['users'] = ['total' => (int)Config::get('nodeinfo', 'total_users'), - 'activeHalfyear' => (int)Config::get('nodeinfo', 'active_users_halfyear'), - 'activeMonth' => (int)Config::get('nodeinfo', 'active_users_monthly')]; - $nodeinfo['usage']['localPosts'] = (int)Config::get('nodeinfo', 'local_posts'); - $nodeinfo['usage']['localComments'] = (int)Config::get('nodeinfo', 'local_comments'); - - if (Addon::isEnabled('blogger')) { - $nodeinfo['services']['outbound'][] = 'blogger'; - } - if (Addon::isEnabled('dwpost')) { - $nodeinfo['services']['outbound'][] = 'dreamwidth'; - } - if (Addon::isEnabled('statusnet')) { - $nodeinfo['services']['inbound'][] = 'gnusocial'; - $nodeinfo['services']['outbound'][] = 'gnusocial'; - } - if (Addon::isEnabled('ijpost')) { - $nodeinfo['services']['outbound'][] = 'insanejournal'; - } - if (Addon::isEnabled('libertree')) { - $nodeinfo['services']['outbound'][] = 'libertree'; - } - if (Addon::isEnabled('buffer')) { - $nodeinfo['services']['outbound'][] = 'linkedin'; - } - if (Addon::isEnabled('ljpost')) { - $nodeinfo['services']['outbound'][] = 'livejournal'; - } - if (Addon::isEnabled('buffer')) { - $nodeinfo['services']['outbound'][] = 'pinterest'; - } - if (Addon::isEnabled('posterous')) { - $nodeinfo['services']['outbound'][] = 'posterous'; - } - if (Addon::isEnabled('pumpio')) { - $nodeinfo['services']['inbound'][] = 'pumpio'; - $nodeinfo['services']['outbound'][] = 'pumpio'; - } - - if ($smtp) { - $nodeinfo['services']['outbound'][] = 'smtp'; - } - if (Addon::isEnabled('tumblr')) { - $nodeinfo['services']['outbound'][] = 'tumblr'; - } - if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) { - $nodeinfo['services']['outbound'][] = 'twitter'; - } - if (Addon::isEnabled('wppost')) { - $nodeinfo['services']['outbound'][] = 'wordpress'; - } - $nodeinfo['metadata']['protocols'] = $nodeinfo['protocols']; - $nodeinfo['metadata']['protocols']['outbound'][] = 'atom1.0'; - $nodeinfo['metadata']['protocols']['inbound'][] = 'atom1.0'; - $nodeinfo['metadata']['protocols']['inbound'][] = 'rss2.0'; - - $nodeinfo['metadata']['services'] = $nodeinfo['services']; - - if (Addon::isEnabled('twitter')) { - $nodeinfo['metadata']['services']['inbound'][] = 'twitter'; - } - - $nodeinfo['metadata']['explicitContent'] = Config::get('system', 'explicit_content', false) == true; - } - - header('Content-type: application/json; charset=utf-8'); - echo json_encode($nodeinfo, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); - exit; -} - - - -function nodeinfo_cron() { - - $a = \get_app(); - - // If the addon 'statistics_json' is enabled then disable it and activate nodeinfo. - if (Addon::isEnabled('statistics_json')) { - Config::set('system', 'nodeinfo', true); - - $addon = 'statistics_json'; - $addons = Config::get('system', 'addon'); - - if ($addons) { - $addons_arr = explode(',',str_replace(' ', '',$addons)); - - $idx = array_search($addon, $addons_arr); - if ($idx !== false) { - unset($addons_arr[$idx]); - Addon::uninstall($addon); - Config::set('system', 'addon', implode(', ',$addons_arr)); - } - } - } - - if (!Config::get('system', 'nodeinfo')) { - return; - } - - Logger::log('cron_start'); - - $users = q("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item` - FROM `user` - INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid` AND `profile`.`is-default` - INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self` - WHERE (`profile`.`publish` OR `profile`.`net-publish`) AND `user`.`verified` - AND NOT `user`.`blocked` AND NOT `user`.`account_removed` - AND NOT `user`.`account_expired`"); - if (is_array($users)) { - $total_users = count($users); - $active_users_halfyear = 0; - $active_users_monthly = 0; - - $halfyear = time() - (180 * 24 * 60 * 60); - $month = time() - (30 * 24 * 60 * 60); - - foreach ($users AS $user) { - if ((strtotime($user['login_date']) > $halfyear) || - (strtotime($user['last-item']) > $halfyear)) { - ++$active_users_halfyear; - } - if ((strtotime($user['login_date']) > $month) || - (strtotime($user['last-item']) > $month)) { - ++$active_users_monthly; - } - } - Config::set('nodeinfo', 'total_users', $total_users); - Config::set('nodeinfo', 'active_users_halfyear', $active_users_halfyear); - Config::set('nodeinfo', 'active_users_monthly', $active_users_monthly); - - Logger::log('total_users: ' . $total_users . '/' . $active_users_halfyear. '/' . $active_users_monthly, Logger::DEBUG); - } - - $local_posts = DBA::count('thread', ["`wall` AND NOT `deleted` AND `uid` != 0"]); - Config::set('nodeinfo', 'local_posts', $local_posts); - Logger::log('local_posts: ' . $local_posts, Logger::DEBUG); - - $local_comments = DBA::count('item', ["`origin` AND `id` != `parent` AND NOT `deleted` AND `uid` != 0"]); - Config::set('nodeinfo', 'local_comments', $local_comments); - Logger::log('local_comments: ' . $local_comments, Logger::DEBUG); - - // Now trying to register - $url = 'http://the-federation.info/register/'.$a->getHostName(); - Logger::log('registering url: '.$url, Logger::DEBUG); - $ret = Network::fetchUrl($url); - Logger::log('registering answer: '.$ret, Logger::DEBUG); - - Logger::log('cron_end'); -} diff --git a/src/Model/Nodeinfo.php b/src/Model/Nodeinfo.php new file mode 100644 index 000000000..60eba2713 --- /dev/null +++ b/src/Model/Nodeinfo.php @@ -0,0 +1,64 @@ +getConfig(); + $logger = $app->getLogger(); + + // If the addon 'statistics_json' is enabled then disable it and activate nodeinfo. + if (Addon::isEnabled('statistics_json')) { + $config->set('system', 'nodeinfo', true); + + $addon = 'statistics_json'; + $addons = $config->get('system', 'addon'); + + if ($addons) { + $addons_arr = explode(',', str_replace(' ', '', $addons)); + + $idx = array_search($addon, $addons_arr); + if ($idx !== false) { + unset($addons_arr[$idx]); + Addon::uninstall($addon); + $config->set('system', 'addon', implode(', ', $addons_arr)); + } + } + } + + if (empty($config->get('system', 'nodeinfo'))) { + return; + } + + $userStats = User::getStatistics(); + + $config->set('nodeinfo', 'total_users', $userStats['total_users']); + $config->set('nodeinfo', 'active_users_halfyear', $userStats['active_users_halfyear']); + $config->set('nodeinfo', 'active_users_monthly', $userStats['active_users_monthly']); + + $logger->debug('user statistics', $userStats); + + $local_posts = DBA::count('thread', ["`wall` AND NOT `deleted` AND `uid` != 0"]); + $config->set('nodeinfo', 'local_posts', $local_posts); + $logger->debug('thread statistics', ['local_posts' => $local_posts]); + + $local_comments = DBA::count('item', ["`origin` AND `id` != `parent` AND NOT `deleted` AND `uid` != 0"]); + $config->set('nodeinfo', 'local_comments', $local_comments); + $logger->debug('item statistics', ['local_comments' => $local_comments]); + } +} diff --git a/src/Model/User.php b/src/Model/User.php index 472ed0924..4b3823f04 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -967,4 +967,51 @@ class User return $identities; } + + /** + * Returns statistical information about the current users of this node + * + * @return array + * + * @throws Exception + */ + public static function getStatistics() + { + $statistics = [ + 'total_users' => 0, + 'active_users_halfyear' => 0, + 'active_users_monthly' => 0, + ]; + + $userStmt = DBA::p("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item` + FROM `user` + INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid` AND `profile`.`is-default` + INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self` + WHERE (`profile`.`publish` OR `profile`.`net-publish`) AND `user`.`verified` + AND NOT `user`.`blocked` AND NOT `user`.`account_removed` + AND NOT `user`.`account_expired`"); + + if (!DBA::isResult($userStmt)) { + return $statistics; + } + + $halfyear = time() - (180 * 24 * 60 * 60); + $month = time() - (30 * 24 * 60 * 60); + + while ($user = DBA::fetch($userStmt)) { + $statistics['total_users']++; + + if ((strtotime($user['login_date']) > $halfyear) || + (strtotime($user['last-item']) > $halfyear)) { + $statistics['active_users_halfyear']++; + } + + if ((strtotime($user['login_date']) > $month) || + (strtotime($user['last-item']) > $month)) { + $statistics['active_users_monthly']++; + } + } + + return $statistics; + } } diff --git a/src/Module/Nodeinfo.php b/src/Module/Nodeinfo.php new file mode 100644 index 000000000..18f2c7280 --- /dev/null +++ b/src/Module/Nodeinfo.php @@ -0,0 +1,169 @@ +getConfig(); + + if (!$config->get('system', 'nodeinfo')) { + System::httpExit(404); + } + + $nodeinfo = [ + 'links' => [[ + 'rel' => 'http://nodeinfo.diaspora.software/ns/schema/1.0', + 'href' => $app->getBaseURL() . '/nodeinfo/1.0']] + ]; + + header('Content-type: application/json; charset=utf-8'); + echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + exit; + } + + public static function init() + { + $app = self::getApp(); + $config = $app->getConfig(); + + if (!$config->get('system', 'nodeinfo')) { + System::httpExit(404); + } + + if (($app->argc != 2) || ($app->argv[1] != '1.0')) { + System::httpExit(404); + } + } + + public static function rawContent() + { + $config = self::getApp()->getConfig(); + + $smtp = (function_exists('imap_open') && !$config->get('system', 'imap_disabled') && !$config->get('system', 'dfrn_only')); + + $nodeinfo = [ + 'version' => 1.0, + 'software' => [ + 'name' => 'friendica', + 'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION, + ], + 'protocols' => [ + 'inbound' => [ + 'friendica', + ], + 'outbound' => [ + 'friendica', + ], + ], + 'services' => [ + 'inbound' => [], + 'outbound' => [], + ], + 'usage' => [], + 'openRegistrations' => intval($config->get('config', 'register_policy')) !== Register::CLOSED, + 'metadata' => [ + 'nodeName' => $config->get('config', 'sitename'), + ], + ]; + + if (!empty($config->get('system', 'diaspora_enabled'))) { + $nodeinfo['protocols']['inbound'][] = 'diaspora'; + $nodeinfo['protocols']['outbound'][] = 'diaspora'; + } + + if (empty($config->get('system', 'ostatus_disabled'))) { + $nodeinfo['protocols']['inbound'][] = 'gnusocial'; + $nodeinfo['protocols']['outbound'][] = 'gnusocial'; + } + + if (!empty($config->get('system', 'nodeinfo'))) { + + $nodeinfo['usage']['users'] = [ + 'total' => intval($config->get('nodeinfo', 'total_users')), + 'activeHalfyear' => intval($config->get('nodeinfo', 'active_users_halfyear')), + 'activeMonth' => intval($config->get('nodeinfo', 'active_users_monthly')) + ]; + $nodeinfo['usage']['localPosts'] = intval($config->get('nodeinfo', 'local_posts')); + $nodeinfo['usage']['localComments'] = intval($config->get('nodeinfo', 'local_comments')); + + if (Addon::isEnabled('blogger')) { + $nodeinfo['services']['outbound'][] = 'blogger'; + } + if (Addon::isEnabled('dwpost')) { + $nodeinfo['services']['outbound'][] = 'dreamwidth'; + } + if (Addon::isEnabled('statusnet')) { + $nodeinfo['services']['inbound'][] = 'gnusocial'; + $nodeinfo['services']['outbound'][] = 'gnusocial'; + } + if (Addon::isEnabled('ijpost')) { + $nodeinfo['services']['outbound'][] = 'insanejournal'; + } + if (Addon::isEnabled('libertree')) { + $nodeinfo['services']['outbound'][] = 'libertree'; + } + if (Addon::isEnabled('buffer')) { + $nodeinfo['services']['outbound'][] = 'linkedin'; + } + if (Addon::isEnabled('ljpost')) { + $nodeinfo['services']['outbound'][] = 'livejournal'; + } + if (Addon::isEnabled('buffer')) { + $nodeinfo['services']['outbound'][] = 'pinterest'; + } + if (Addon::isEnabled('posterous')) { + $nodeinfo['services']['outbound'][] = 'posterous'; + } + if (Addon::isEnabled('pumpio')) { + $nodeinfo['services']['inbound'][] = 'pumpio'; + $nodeinfo['services']['outbound'][] = 'pumpio'; + } + + if ($smtp) { + $nodeinfo['services']['outbound'][] = 'smtp'; + } + if (Addon::isEnabled('tumblr')) { + $nodeinfo['services']['outbound'][] = 'tumblr'; + } + if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) { + $nodeinfo['services']['outbound'][] = 'twitter'; + } + if (Addon::isEnabled('wppost')) { + $nodeinfo['services']['outbound'][] = 'wordpress'; + } + $nodeinfo['metadata']['protocols'] = $nodeinfo['protocols']; + $nodeinfo['metadata']['protocols']['outbound'][] = 'atom1.0'; + $nodeinfo['metadata']['protocols']['inbound'][] = 'atom1.0'; + $nodeinfo['metadata']['protocols']['inbound'][] = 'rss2.0'; + + $nodeinfo['metadata']['services'] = $nodeinfo['services']; + + if (Addon::isEnabled('twitter')) { + $nodeinfo['metadata']['services']['inbound'][] = 'twitter'; + } + + $nodeinfo['metadata']['explicitContent'] = $config->get('system', 'explicit_content', false) == true; + } + + header('Content-type: application/json; charset=utf-8'); + echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + exit; + } +} diff --git a/src/Worker/CronJobs.php b/src/Worker/CronJobs.php index d0f417f4f..72d194808 100644 --- a/src/Worker/CronJobs.php +++ b/src/Worker/CronJobs.php @@ -16,10 +16,12 @@ use Friendica\Database\DBA; use Friendica\Database\PostUpdate; use Friendica\Model\Contact; use Friendica\Model\GContact; +use Friendica\Model\Nodeinfo; use Friendica\Model\Photo; use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; +use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; require_once 'mod/nodeinfo.php'; @@ -43,7 +45,14 @@ class CronJobs break; case 'nodeinfo': - nodeinfo_cron(); + Logger::info('cron_start'); + Nodeinfo::update(); + // Now trying to register + $url = 'http://the-federation.info/register/' . $a->getHostName(); + Logger::debug('Check registering url', ['url' => $url]); + $ret = Network::fetchUrl($url); + Logger::debug('Check registering answer', ['answer' => $ret]); + Logger::info('cron_end'); break; case 'expire_and_remove_users':