]> git.mxchange.org Git - friendica.git/blob - src/Module/Admin/Federation.php
Possibly Avoid database error when storing photo item
[friendica.git] / src / Module / Admin / Federation.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Module\Admin;
23
24 use Friendica\Core\Renderer;
25 use Friendica\Database\DBA;
26 use Friendica\DI;
27 use Friendica\Module\BaseAdmin;
28
29 class Federation extends BaseAdmin
30 {
31         protected function content(array $request = []): string
32         {
33                 parent::content();
34
35                 // get counts on active federation systems this node is knowing
36                 // We list the more common systems by name. The rest is counted as "other"
37                 $systems = [
38                         'friendica'   => ['name' => 'Friendica', 'color' => '#ffc018'], // orange from the logo
39                         'diaspora'    => ['name' => 'Diaspora', 'color' => '#a1a1a1'], // logo is black and white, makes a gray
40                         'funkwhale'   => ['name' => 'Funkwhale', 'color' => '#4082B4'], // From the homepage
41                         'gnusocial'   => ['name' => 'GNU Social/Statusnet', 'color' => '#a22430'], // dark red from the logo
42                         'hubzilla'    => ['name' => 'Hubzilla/Red Matrix', 'color' => '#43488a'], // blue from the logo
43                         'mastodon'    => ['name' => 'Mastodon', 'color' => '#1a9df9'], // blue from the Mastodon logo
44                         'misskey'     => ['name' => 'Misskey', 'color' => '#ccfefd'], // Font color of the homepage
45                         'mobilizon'   => ['name' => 'Mobilizon', 'color' => '#ffd599'], // Background color of parts of the homepage
46                         'nextcloud'   => ['name' => 'Nextcloud', 'color' => '#1cafff'], // Logo color
47                         'peertube'    => ['name' => 'Peertube', 'color' => '#ffad5c'], // One of the logo colors
48                         'pixelfed'    => ['name' => 'Pixelfed', 'color' => '#11da47'], // One of the logo colors
49                         'pleroma'     => ['name' => 'Pleroma', 'color' => '#E46F0F'], // Orange from the text that is used on Pleroma instances
50                         'plume'       => ['name' => 'Plume', 'color' => '#7765e3'], // From the homepage
51                         'socialhome'  => ['name' => 'SocialHome', 'color' => '#52056b'], // lilac from the Django Image used at the Socialhome homepage
52                         'wordpress'   => ['name' => 'WordPress', 'color' => '#016087'], // Background color of the homepage
53                         'writefreely' => ['name' => 'WriteFreely', 'color' => '#292929'], // Font color of the homepage
54                         'mistpark'    => ['name' => 'Nomad projects (Mistpark, Osada, Roadhouse, Zap)', 'color' => '#348a4a'], // Green like the Mistpark green
55                         'relay'       => ['name' => 'ActivityPub Relay', 'color' => '#888888'], // Grey like the second color of the ActivityPub logo
56                         'other'       => ['name' => DI::l10n()->t('Other'), 'color' => '#F1007E'], // ActivityPub main color
57                 ];
58
59                 $platforms = array_keys($systems);
60
61                 $counts = [];
62                 foreach ($platforms as $platform) {
63                         $counts[$platform] = [];
64                 }
65
66                 $total = 0;
67                 $users = 0;
68
69                 $gservers = DBA::p("SELECT COUNT(*) AS `total`, SUM(`registered-users`) AS `users`, `platform`,
70                         ANY_VALUE(`network`) AS `network`, MAX(`version`) AS `version`
71                         FROM `gserver` WHERE NOT `failed` GROUP BY `platform`");
72                 while ($gserver = DBA::fetch($gservers)) {
73                         $total += $gserver['total'];
74                         $users += $gserver['users'];
75
76                         $versionCounts = [];
77                         $versions = DBA::p("SELECT COUNT(*) AS `total`, `version` FROM `gserver`
78                                 WHERE NOT `failed` AND `platform` = ?
79                                 GROUP BY `version` ORDER BY `version`", $gserver['platform']);
80                         while ($version = DBA::fetch($versions)) {
81                                 $version['version'] = str_replace(["\n", "\r", "\t"], " ", $version['version']);
82
83                                 if (in_array($gserver['platform'], ['Red Matrix', 'redmatrix', 'red'])) {
84                                         $version['version'] = 'Red ' . $version['version'];
85                                 } elseif (in_array($gserver['platform'], ['osada', 'mistpark', 'roadhouse', 'zap'])) {
86                                         $version['version'] = $gserver['platform'] . ' ' . $version['version'];
87                                 } elseif (in_array($gserver['platform'], ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
88                                         $version['version'] = $gserver['platform'] . '-' . $version['version'];
89                                 }
90
91                                 $versionCounts[] = $version;
92                         }
93                         DBA::close($versions);
94
95                         $platform = $gserver['platform'] = strtolower($gserver['platform']);
96
97                         if ($platform == 'friendika') {
98                                 $platform = 'friendica';
99                         } elseif (in_array($platform, ['red matrix', 'redmatrix', 'red'])) {
100                                 $platform = 'hubzilla';
101                         } elseif (in_array($platform, ['mistpark', 'osada', 'roadhouse', 'zap'])) {
102                                 $platform = 'mistpark';
103                         } elseif(stristr($platform, 'pleroma')) {
104                                 $platform = 'pleroma';
105                         } elseif(stristr($platform, 'statusnet')) {
106                                 $platform = 'gnusocial';
107                         } elseif(stristr($platform, 'wordpress')) {
108                                 $platform = 'wordpress';
109                         } elseif (in_array($platform, ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
110                                 $platform = 'relay';
111                         } elseif (!in_array($platform, $platforms)) {
112                                 $platform = 'other';
113                         }
114
115                         if ($platform != $gserver['platform']) {
116                                 if ($platform == 'other') {
117                                         $versionCounts = $counts[$platform][1] ?? [];
118                                         $versionCounts[] = ['version' => $gserver['platform'] ?: DI::l10n()->t('unknown'), 'total' => $gserver['total']];
119                                         $gserver['version'] = '';
120                                 } else {
121                                         $versionCounts = array_merge($versionCounts, $counts[$platform][1] ?? []);
122                                 }
123
124                                 $gserver['platform'] = $platform;
125                                 $gserver['total'] += $counts[$platform][0]['total'] ?? 0;
126                                 $gserver['users'] += $counts[$platform][0]['users'] ?? 0;
127                         }
128
129                         if ($platform == 'friendica') {
130                                 $versionCounts = self::reformaFriendicaVersions($versionCounts);
131                         } elseif ($platform == 'pleroma') {
132                                 $versionCounts = self::reformaPleromaVersions($versionCounts);
133                         } elseif ($platform == 'diaspora') {
134                                 $versionCounts = self::reformaDiasporaVersions($versionCounts);
135                         } elseif ($platform == 'relay') {
136                                 $versionCounts = self::reformatRelayVersions($versionCounts);
137                         } elseif (in_array($platform, ['funkwhale', 'mastodon', 'mobilizon', 'misskey'])) {
138                                 $versionCounts = self::removeVersionSuffixes($versionCounts);
139                         }
140
141                         if (!in_array($platform, ['other', 'relay', 'mistpark'])) {
142                                 $versionCounts = self::sortVersion($versionCounts);
143                         } else {
144                                 ksort($versionCounts);
145                         }
146
147                         $gserver['platform'] = $systems[$platform]['name'];
148
149                         $counts[$platform] = [$gserver, $versionCounts, str_replace([' ', '%'], '', $platform), $systems[$platform]['color']];
150                 }
151                 DBA::close($gserver);
152
153                 // some helpful text
154                 $intro = DI::l10n()->t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
155
156                 // load the template, replace the macros and return the page content
157                 $t = Renderer::getMarkupTemplate('admin/federation.tpl');
158                 return Renderer::replaceMacros($t, [
159                         '$title' => DI::l10n()->t('Administration'),
160                         '$page' => DI::l10n()->t('Federation Statistics'),
161                         '$intro' => $intro,
162                         '$counts' => $counts,
163                         '$version' => FRIENDICA_VERSION,
164                         '$legendtext' => DI::l10n()->t('Currently this node is aware of %d nodes with %d registered users from the following platforms:', $total, $users),
165                 ]);
166         }
167
168         /**
169          * early friendica versions have the format x.x.xxxx where xxxx is the
170          * DB version stamp; those should be operated out and versions be combined
171          *
172          * @param array $versionCounts list of version numbers
173          * @return array with cleaned version numbers
174          */
175         private static function reformaFriendicaVersions(array $versionCounts)
176         {
177                 $newV = [];
178                 $newVv = [];
179                 foreach ($versionCounts as $vv) {
180                         $newVC = $vv['total'];
181                         $newVV = $vv['version'];
182                         $lastDot = strrpos($newVV, '.');
183                         $firstDash = strpos($newVV, '-');
184                         $len = strlen($newVV) - 1;
185                         if (($lastDot == $len - 4) && (!strrpos($newVV, '-rc') == $len - 3) && (!$firstDash == $len - 1)) {
186                                 $newVV = substr($newVV, 0, $lastDot);
187                         }
188                         if (isset($newV[$newVV])) {
189                                 $newV[$newVV] += $newVC;
190                         } else {
191                                 $newV[$newVV] = $newVC;
192                         }
193                 }
194                 foreach ($newV as $key => $value) {
195                         array_push($newVv, ['total' => $value, 'version' => $key]);
196                 }
197                 $versionCounts = $newVv;
198
199                 return $versionCounts;
200         }
201
202         /**
203          * in the DB the Diaspora versions have the format x.x.x.x-xx the last
204          * part (-xx) should be removed to clean up the versions from the "head
205          * commit" information and combined into a single entry for x.x.x.x
206          *
207          * @param array $versionCounts list of version numbers
208          * @return array with cleaned version numbers
209          */
210         private static function reformaDiasporaVersions(array $versionCounts)
211         {
212                 $newV = [];
213                 $newVv = [];
214                 foreach ($versionCounts as $vv) {
215                         $newVC = $vv['total'];
216                         $newVV = $vv['version'];
217                         $posDash = strpos($newVV, '-');
218                         if ($posDash) {
219                                 $newVV = substr($newVV, 0, $posDash);
220                         }
221                         if (isset($newV[$newVV])) {
222                                 $newV[$newVV] += $newVC;
223                         } else {
224                                 $newV[$newVV] = $newVC;
225                         }
226                 }
227                 foreach ($newV as $key => $value) {
228                         array_push($newVv, ['total' => $value, 'version' => $key]);
229                 }
230                 $versionCounts = $newVv;
231
232                 return $versionCounts;
233         }
234
235         /**
236          * Clean up Pleroma version numbers
237          *
238          * @param array $versionCounts list of version numbers
239          * @return array with cleaned version numbers
240          */
241         private static function reformaPleromaVersions(array $versionCounts)
242         {
243                 $compacted = [];
244                 foreach ($versionCounts as $key => $value) {
245                         $version = $versionCounts[$key]['version'];
246                         $parts = explode(' ', trim($version));
247                         do {
248                                 $part = array_pop($parts);
249                         } while (!empty($parts) && ((strlen($part) >= 40) || (strlen($part) <= 3)));
250                         // only take the x.x.x part of the version, not the "release" after the dash
251                         if (!empty($part) && strpos($part, '-')) {
252                                 $part = explode('-', $part)[0];
253                         }
254                         if (!empty($part)) {
255                                 if (empty($compacted[$part])) {
256                                         $compacted[$part] = $versionCounts[$key]['total'];
257                                 } else {
258                                         $compacted[$part] += $versionCounts[$key]['total'];
259                                 }
260                         }
261                 }
262
263                 $versionCounts = [];
264                 foreach ($compacted as $version => $pl_total) {
265                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
266                 }
267
268                 return $versionCounts;
269         }
270
271         /**
272          * Clean up version numbers
273          *
274          * @param array $versionCounts list of version numbers
275          * @return array with cleaned version numbers
276          */
277         private static function removeVersionSuffixes(array $versionCounts)
278         {
279                 $compacted = [];
280                 foreach ($versionCounts as $key => $value) {
281                         $version = $versionCounts[$key]['version'];
282
283                         foreach ([' ', '+', '-', '#', '_', '~'] as $delimiter) {
284                                 $parts = explode($delimiter, trim($version));
285                                 $version = array_shift($parts);
286                         }
287
288                         if (empty($compacted[$version])) {
289                                 $compacted[$version] = $versionCounts[$key]['total'];
290                         } else {
291                                 $compacted[$version] += $versionCounts[$key]['total'];
292                         }
293                 }
294
295                 $versionCounts = [];
296                 foreach ($compacted as $version => $pl_total) {
297                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
298                 }
299
300                 return $versionCounts;
301         }
302
303         /**
304          * Clean up relay version numbers
305          *
306          * @param array $versionCounts list of version numbers
307          * @return array with cleaned version numbers
308          */
309         private static function reformatRelayVersions(array $versionCounts)
310         {
311                 $compacted = [];
312                 foreach ($versionCounts as $key => $value) {
313                         $version = $versionCounts[$key]['version'];
314
315                         $parts = explode(' ', trim($version));
316                         $version = array_shift($parts);
317
318                         if (empty($compacted[$version])) {
319                                 $compacted[$version] = $versionCounts[$key]['total'];
320                         } else {
321                                 $compacted[$version] += $versionCounts[$key]['total'];
322                         }
323                 }
324
325                 $versionCounts = [];
326                 foreach ($compacted as $version => $pl_total) {
327                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
328                 }
329
330                 return $versionCounts;
331         }
332
333         /**
334          * Reformat, sort and compact version numbers
335          *
336          * @param array $versionCounts list of version numbers
337          * @return array with reformatted version numbers
338          */
339         private static function sortVersion(array $versionCounts)
340         {
341                 //
342                 // clean up version numbers
343                 //
344                 // some platforms do not provide version information, add a unkown there
345                 // to the version string for the displayed list.
346                 foreach ($versionCounts as $key => $value) {
347                         if ($versionCounts[$key]['version'] == '') {
348                                 $versionCounts[$key] = ['total' => $versionCounts[$key]['total'], 'version' => DI::l10n()->t('unknown')];
349                         }
350                 }
351
352                 // Assure that the versions are sorted correctly
353                 $v2 = [];
354                 $versions = [];
355                 foreach ($versionCounts as $vv) {
356                         $version = trim(strip_tags($vv["version"]));
357                         $v2[$version] = $vv;
358                         $versions[] = $version;
359                 }
360
361                 usort($versions, 'version_compare');
362
363                 $versionCounts = [];
364                 foreach ($versions as $version) {
365                         $versionCounts[] = $v2[$version];
366                 }
367
368                 return $versionCounts;
369         }
370 }