Compare commits

..

No commits in common. "master" and "v0.7.1" have entirely different histories.

12 changed files with 180 additions and 375 deletions

View File

@ -1,51 +1,3 @@
DotclearWatch 0.9.3 - 2023.10.22
===========================================================
* Require dotclear 2.28
* Require php 8.1
* Add PHP minor version (using PHP constants)
* Add uninstall feature (plugin Uninstaller)
* Fix colored synthax
* Use Helper Form everywhere
DotclearWatch 0.9.2 - 2023.10.14
===========================================================
* Require dotclear 2.28
* Require php 8.1
* Fix last minute update from Dtoclear 2.28
DotclearWatch 0.9.1 - 2023.10.09
===========================================================
* Require dotclear 2.28
* Require php 8.1
* Fix permissions
* Code review
DotclearWatch 0.9 - 2023.10.07
===========================================================
* Require dotclear 2.28
* Require php 8.1
* Update to Dotclear 2.28-dev
DotclearWatch 0.8 - 2023.08.27
===========================================================
* Require dotclear 2.27
* Require php 7.4
* Add web server name and version to stats
DotclearWatch 0.7.2 - 2023.08.26
===========================================================
* Require dotclear 2.27
* Require php 7.4
* fix type hint
* fix README
DotclearWatch 0.7.2 - 2023.08.16
===========================================================
* Require dotclear 2.27
* Require php 7.4
* Fix unset user prefs
* Change page footer
DotclearWatch 0.7.1 - 2023.08.14 DotclearWatch 0.7.1 - 2023.08.14
=========================================================== ===========================================================
* Require dotclear 2.27 * Require dotclear 2.27

View File

@ -1,16 +1,15 @@
# README # README
[![Release](https://img.shields.io/badge/release-0.9.3-a2cbe9.svg)](https://git.dotclear.watch/dw/DotclearWatch/releases) [![Release](https://img.shields.io/badge/release-0.7-a2cbe9.svg)](https://git.dotclear.watch/dw/DotclearWatch/releases)
![Date](https://img.shields.io/badge/date-2023.10.22-c44d58.svg) [![Date](https://img.shields.io/badge/date-2023.08.12-c44d58.svg)](https://git.dotclear.watch/dw/DotclearWatch/releases)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download) [![Dotclear](https://img.shields.io/badge/dotclear-v2.27-137bbb.svg)](https://fr.dotclear.org/download)
[![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/DotclearWatch) [![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/DotclearWatch)
[![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/dw/DotclearWatch/src/branch/master/LICENSE) [![License](https://img.shields.io/github/license/JcDenis/DotclearWatch)](https://git.dotclear.watch/dw/DotclearWatch/blob/master/LICENSE)
## ABOUT ## WHAT IS DOTCLEARWATCH ?
_dotclear watch_ is a plugin for the open-source web publishing software called [Dotclear](https://www.dotclear.org). "dotclear watch" is a plugin for the open-source
web publishing software called Dotclear.
> Send report about your Dotclear
It tracks Dotclear's installation to get stats about it. It tracks Dotclear's installation to get stats about it.
Default statistics server is located at https://stat.dotclear.watch Default statistics server is located at https://stat.dotclear.watch
@ -29,9 +28,11 @@ in aboutConfig global parameters called DotclearWatch->hidden_modules
## REQUIREMENTS ## REQUIREMENTS
* Dotclear 2.28 DotclearWatch requires:
* PHP 8.1+
* Dotclear super admin permission to intall it * super admin permission to intall it
* Dotclear 2.27
* PHP 7.4+
## USAGE ## USAGE
@ -42,10 +43,10 @@ To disable sending stats, just deactivate or uninstall this plugin.
## LINKS ## LINKS
* [License](https://git.dotclear.watch/dw/DotclearWatch/src/branch/master/LICENSE) * License : [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html)
* [Packages & details](https://git.dotclear.watch/dw/DotclearWatch/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/DotclearWatch)) * Source & contributions : [Gitea Page](https://git.dotclear.watch/dw/DotclearWatch) or [GitHub Page](https://github.com/JcDenis/DotclearWatch)
* [Sources & contributions](https://git.dotclear.watch/dw/DotclearWatch) (or on [GitHub](https://github.com/JcDenis/DotclearWatch)) * Packages & details : [Gitea Page](https://git.dotclear.watch/dw/DotclearWatch/releases) or[Dotaddict Page](https://plugins.dotaddict.org/dc2/details/DotclearWatch)
* [Issues & security](https://git.dotclear.watch/dw/DotclearWatch/issues) (or on [GitHub](https://github.com/JcDenis/DotclearWatch/issues)) * Discussion & Help : [Gitea Page](https://github.com/dw/DotclearWatch/issues)
## CONTRIBUTORS ## CONTRIBUTORS

View File

@ -1,30 +1,28 @@
<?php <?php
/** /**
* @file * @brief DotclearWatch, a plugin for Dotclear 2
* @brief The plugin DotclearWatch definition
* @ingroup DotclearWatch
* *
* @defgroup DotclearWatch Plugin DotclearWatch. * @package Dotclear
* @subpackage Plugin
* *
* QSend report about your Dotclear. * @author Jean-Christian Denis and contributors
* *
* @author Jean-Christian Denis * @copyright Jean-Christain Denis
* @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
$this->registerModule( $this->registerModule(
'Dotclear Watch', 'Dotclear Watch',
'Send report about your Dotclear', 'Send report about your Dotclear',
'Jean-Christian Denis and contributors', 'Jean-Christian Denis and contributors',
'0.9.3', '0.7.1',
[ [
'requires' => [['core', '2.28']], 'requires' => [
'permissions' => 'My', ['php', '7.4'],
'type' => 'plugin', ['core', '2.27'],
'support' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/issues', ],
'details' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/src/branch/master/README.md', 'type' => 'plugin',
'repository' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/raw/branch/master/dcstore.xml', 'support' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/issues',
'details' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/src/branch/master/README.md',
'repository' => 'https://git.dotclear.watch/dw/' . basename(__DIR__) . '/raw/branch/master/dcstore.xml',
] ]
); );

View File

@ -2,11 +2,11 @@
<modules xmlns:da="http://dotaddict.org/da/"> <modules xmlns:da="http://dotaddict.org/da/">
<module id="DotclearWatch"> <module id="DotclearWatch">
<name>Dotclear Watch</name> <name>Dotclear Watch</name>
<version>0.9.3</version> <version>0.7.1</version>
<author>Jean-Christian Denis and contributors</author> <author>Jean-Christian Denis and contributors</author>
<desc>Send report about your Dotclear</desc> <desc>Send report about your Dotclear</desc>
<file>https://git.dotclear.watch/dw/DotclearWatch/releases/download/v0.9.3/plugin-DotclearWatch.zip</file> <file>https://git.dotclear.watch/dw/DotclearWatch/releases/download/v0.7.1/plugin-DotclearWatch.zip</file>
<da:dcmin>2.28</da:dcmin> <da:dcmin>2.27</da:dcmin>
<da:details>https://git.dotclear.watch/dw/DotclearWatch/src/branch/master/README.md</da:details> <da:details>https://git.dotclear.watch/dw/DotclearWatch/src/branch/master/README.md</da:details>
<da:support>https://git.dotclear.watch/dw/DotclearWatch/issues</da:support> <da:support>https://git.dotclear.watch/dw/DotclearWatch/issues</da:support>
</module> </module>

View File

@ -11,8 +11,6 @@
use Dotclear\Helper\L10n; use Dotclear\Helper\L10n;
L10n::$locales['Uses DotclearWatch plugin statistics'] = 'Utilise le plugin de statistiques DotclearWatch';
L10n::$locales['Shared statistics'] = 'Statistiques partagées';
L10n::$locales['Cache directory sucessfully cleared.'] = 'Répertoire de cache des rapports nettoyé.'; L10n::$locales['Cache directory sucessfully cleared.'] = 'Répertoire de cache des rapports nettoyé.';
L10n::$locales['Settings successfully updated.'] = 'Paramètres mis à jour.'; L10n::$locales['Settings successfully updated.'] = 'Paramètres mis à jour.';
L10n::$locales['Report sent.'] = 'Rapport envoyé.'; L10n::$locales['Report sent.'] = 'Rapport envoyé.';

View File

@ -1,21 +1,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: DotclearWatch 0.7.1\n" "Project-Id-Version: DotclearWatch 0.1\n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: 2023-08-16T14:14:45+00:00\n" "PO-Revision-Date: 2023-07-23T09:13:29+00:00\n"
"Last-Translator: Jean-Christain Denis\n" "Last-Translator: Jean-Christain Denis\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Uses DotclearWatch plugin statistics"
msgstr "Utilise le plugin de statistiques DotclearWatch"
msgid "Shared statistics"
msgstr "Statistiques partagées"
msgid "Cache directory sucessfully cleared." msgid "Cache directory sucessfully cleared."
msgstr "Répertoire de cache des rapports nettoyé." msgstr "Répertoire de cache des rapports nettoyé."

View File

@ -1,25 +1,22 @@
<?php <?php
/**
* @brief DotclearWatch, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christain Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch; namespace Dotclear\Plugin\DotclearWatch;
use Dotclear\App; use dcCore;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Helper\Html\Form\{
Img,
Li,
Link,
Ul
};
/**
* @brief DotclearWatch backend class.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Backend extends Process class Backend extends Process
{ {
public static function init(): bool public static function init(): bool
@ -33,32 +30,14 @@ class Backend extends Process
return false; return false;
} }
App::behavior()->addBehaviors([ dcCore::app()->addBehaviors([
// Add JS for asynchronous report sending
'adminDashboardHeaders' => function (): string { 'adminDashboardHeaders' => function (): string {
return My::jsLoad('service', App::version()->getVersion(My::id())); return My::jsLoad('service', dcCore::app()->getVersion(My::id()));
},
// Add icon on bottom of dashboard sidebar menu
'adminPageFooterV2' => function (): void {
if (My::settings()->getGlobal('distant_api_url')) {
echo (new Ul())->items([
(new li())->items([
(new Link())
->class('outgoing')
->href('https://stat.dotclear.watch')
->title(__('Uses DotclearWatch plugin statistics'))
->text(__('Shared statistics'))
->items([
(new Img(My::fileURL('icon.svg'))),
]),
]),
])->render();
}
}, },
'adminPageFooterV2' => [Utils::class, 'addMark'],
]); ]);
App::rest()->addFunction( dcCore::app()->rest->addFunction(
// Add REST service for asynchronous report sending
'adminDotclearWatchSendReport', 'adminDotclearWatchSendReport',
function (): array { function (): array {
Utils::sendReport(); Utils::sendReport();

View File

@ -1,10 +1,18 @@
<?php <?php
/**
* @brief DotclearWatch, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugins
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch; namespace Dotclear\Plugin\DotclearWatch;
use Dotclear\App; use dcCore;
use Dotclear\Core\Backend\Notices; use Dotclear\Core\Backend\Notices;
use Dotclear\Core\Backend\Page; use Dotclear\Core\Backend\Page;
use Dotclear\Core\Process; use Dotclear\Core\Process;
@ -22,32 +30,14 @@ use Dotclear\Helper\Html\Form\{
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
/**
* @brief DotclearWatch configuration class.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Config extends Process class Config extends Process
{ {
/** private static string $hidden_modules = '';
* List of hidden modules.
*
* @var string $hidden_modules
*/
private static string $hidden_modules = '';
/**
* Distant API URL.
*
* @var string $distant_api_url
*/
private static string $distant_api_url = ''; private static string $distant_api_url = '';
public static function init(): bool public static function init(): bool
{ {
return self::status(My::checkContext(My::CONFIG)); return self::status(My::checkContext(My::MANAGE));
} }
public static function process(): bool public static function process(): bool
@ -56,8 +46,8 @@ class Config extends Process
return false; return false;
} }
if (App::auth()->prefs()->get('interface')->get('colorsyntax')) { if (dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax')) {
App::behavior()->addBehavior('pluginsToolsHeadersV2', fn (bool $plugin): string => Page::jsLoadCodeMirror(App::auth()->prefs()->get('interface')->get('colorsyntax_theme'))); dcCore::app()->addBehavior('pluginsToolsHeadersV2', fn (bool $plugin): string => Page::jsLoadCodeMirror(dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme')));
} }
self::$hidden_modules = (string) My::settings()->getGlobal('hidden_modules'); self::$hidden_modules = (string) My::settings()->getGlobal('hidden_modules');
@ -72,8 +62,7 @@ class Config extends Process
Notices::AddSuccessNotice(__('Cache directory sucessfully cleared.')); Notices::AddSuccessNotice(__('Cache directory sucessfully cleared.'));
} }
self::$distant_api_url = !empty($_POST['distant_api_url']) && is_string($_POST['distant_api_url']) ? $_POST['distant_api_url'] : Utils::DISTANT_API_URL; self::$hidden_modules = '';
self::$hidden_modules = '';
foreach (explode(',', $_POST['hidden_modules']) as $hidden) { foreach (explode(',', $_POST['hidden_modules']) as $hidden) {
$hidden = trim($hidden); $hidden = trim($hidden);
if (!empty($hidden)) { if (!empty($hidden)) {
@ -81,6 +70,8 @@ class Config extends Process
} }
} }
self::$distant_api_url = !empty($_POST['distant_api_url']) && is_string($_POST['distant_api_url']) ? $_POST['distant_api_url'] : Utils::DISTANT_API_URL;
My::settings()->put('hidden_modules', self::$hidden_modules, 'string', 'Hidden modules from report', true, true); My::settings()->put('hidden_modules', self::$hidden_modules, 'string', 'Hidden modules from report', true, true);
My::settings()->put('distant_api_url', self::$distant_api_url, 'string', 'Distant API report URL', true, true); My::settings()->put('distant_api_url', self::$distant_api_url, 'string', 'Distant API report URL', true, true);
Notices::AddSuccessNotice(__('Settings successfully updated.')); Notices::AddSuccessNotice(__('Settings successfully updated.'));
@ -95,7 +86,7 @@ class Config extends Process
} }
} }
App::backend()->url()->redirect('admin.plugins', ['module' => My::id(), 'conf' => '1']); dcCore::app()->admin->url->redirect('admin.plugins', ['module' => My::id(), 'conf' => '1']);
return true; return true;
} }
@ -115,12 +106,12 @@ class Config extends Process
]), ]),
(new Para())->items([ (new Para())->items([
(new Label(__('Hidden modules:')))->for('hidden_modules'), (new Label(__('Hidden modules:')))->for('hidden_modules'),
(new Input('hidden_modules'))->class('maximal')->size(65)->maxlength(255)->value(self::$hidden_modules), (new Input('hidden_modules'))->class('maximal')->size(65)->maxlenght(255)->value(self::$hidden_modules),
]), ]),
(new Note())->class('form-note')->text(__('This is the comma separated list of plugins IDs and themes IDs to ignore in report.')), (new Note())->class('form-note')->text(__('This is the comma separated list of plugins IDs and themes IDs to ignore in report.')),
(new Para())->items([ (new Para())->items([
(new Label(__('Distant API URL:')))->for('distant_api_url'), (new Label(__('Distant API URL:')))->for('distant_api_url'),
(new Input('distant_api_url'))->class('maximal')->size(65)->maxlength(255)->value(self::$distant_api_url), (new Input('distant_api_url'))->class('maximal')->size(65)->maxlenght(255)->value(self::$distant_api_url),
]), ]),
(new Note())->class('form-note')->text(__('This is the URL of the API to send report. Leave empty to reset value.')), (new Note())->class('form-note')->text(__('This is the URL of the API to send report. Leave empty to reset value.')),
(new Para())->items([ (new Para())->items([
@ -147,8 +138,8 @@ class Config extends Process
->class('maximal'), ->class('maximal'),
])->render() . ])->render() .
( (
App::auth()->prefs()->get('interface')->get('colorsyntax') ? !dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax') ? '' :
Page::jsRunCodeMirror(My::id() . 'editor', 'report_contents', 'json', App::auth()->prefs()->get('interface')->get('colorsyntax_theme')) : '' Page::jsRunCodeMirror(My::id() . 'editor', 'report_contents', 'json', dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme'))
); );
} }
} }

View File

@ -1,18 +1,21 @@
<?php <?php
/**
* @brief DotclearWatch, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christain Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch; namespace Dotclear\Plugin\DotclearWatch;
use Dotclear\Core\Process; use Dotclear\Core\Process;
/**
* @brief DotclearWatch install class.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Install extends Process class Install extends Process
{ {
public static function init(): bool public static function init(): bool
@ -22,8 +25,9 @@ class Install extends Process
public static function process(): bool public static function process(): bool
{ {
if (self::status()) { $s = My::settings();
My::settings()->put( if (self::status() && $s !== null) {
$s->put(
'hidden_modules', 'hidden_modules',
'DotclearWatch', 'DotclearWatch',
'string', 'string',
@ -31,7 +35,7 @@ class Install extends Process
false, false,
true true
); );
My::settings()->put( $s->put(
'distant_api_url', 'distant_api_url',
'https://dotclear.watch/api', 'https://dotclear.watch/api',
'string', 'string',

View File

@ -1,19 +1,27 @@
<?php <?php
/**
* @brief DotclearWatch, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christain Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch; namespace Dotclear\Plugin\DotclearWatch;
use dcCore;
use Dotclear\Module\MyPlugin; use Dotclear\Module\MyPlugin;
/**
* @brief DotclearWatch My helper.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class My extends MyPlugin class My extends MyPlugin
{ {
// Use default permissions protected static function checkCustomContext(int $context): ?bool
{
return $context === My::INSTALL ? null :
defined('DC_CONTEXT_ADMIN') && dcCore::app()->auth->isSuperAdmin();
}
} }

View File

@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch;
use Dotclear\Core\Process;
use Dotclear\Plugin\Uninstaller\Uninstaller;
/**
* @brief DotclearWatch uninstall class.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Uninstall extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::UNINSTALL));
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
Uninstaller::instance()
->addUserAction(
'settings',
'delete_all',
My::id()
)
->addUserAction(
'plugins',
'delete',
My::id()
)
->addUserAction(
'versions',
'delete',
My::id()
)
->addDirectAction(
'settings',
'delete_all',
My::id()
)
->addDirectAction(
'plugins',
'delete',
My::id()
)
->addDirectAction(
'versions',
'delete',
My::id()
)
;
// no custom action
return false;
}
}

View File

@ -1,59 +1,61 @@
<?php <?php
/**
* @brief DotclearWatch, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christain Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\DotclearWatch; namespace Dotclear\Plugin\DotclearWatch;
use Dotclear\App; use dcCore;
use dcLog;
use dcModuleDefine;
use dcThemes;
use Dotclear\Helper\Crypt; use Dotclear\Helper\Crypt;
use Dotclear\Helper\Date;
use Dotclear\Helper\Network\HttpClient; use Dotclear\Helper\Network\HttpClient;
use Dotclear\Module\ModuleDefine;
use Exception; use Exception;
/**
* @brief DotclearWatch utils class.
* @ingroup DotclearWatch
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Utils class Utils
{ {
/** /** @var int The expiration delay before resend report (one week) */
* The expiration delay before resend report (one week).
*
* @var int EXPIRED_DELAY
*/
public const EXPIRED_DELAY = 604800; public const EXPIRED_DELAY = 604800;
/** /** @var string The default distant API URL */
* The default distant API URL.
*
* @var string DISTANT_API_URL
*/
public const DISTANT_API_URL = 'https://dotclear.watch/api'; public const DISTANT_API_URL = 'https://dotclear.watch/api';
/** /** @var string The distant API version */
* The distant API version.
*
* @var string DISTANT_API_VERSION
*/
public const DISTANT_API_VERSION = '1.1'; public const DISTANT_API_VERSION = '1.1';
/** /** @var array<int,string> The hiddens modules IDs */
* The hiddens modules IDs.
*
* @var array<int,string> $hiddens
*/
private static array $hiddens = []; private static array $hiddens = [];
/** /** @var string Multiblog unique identifiant */
* Multiblog unique identifiant.
*
* @var string $uid
*/
private static string $uid = ''; private static string $uid = '';
/**
* Add mark to backend menu footer.
*/
public static function addMark(): void
{
if (My::settings()->getGlobal('distant_api_url')) {
echo sprintf(
'<ul><li><a href="%s" title="%s" class="outgoing">%s<img src="%s" /></a></ul></li>',
'https://stat.dotclear.watch',
__('DotclearWatch plugin statistics'),
__('Tracked by dotclear.watch'),
My::fileURL('icon.svg')
);
}
}
/** /**
* Get hidden modules. * Get hidden modules.
* *
@ -86,12 +88,12 @@ class Utils
{ {
$modules = []; $modules = [];
$hiddens = self::getHiddens(); $hiddens = self::getHiddens();
$defines = App::plugins()->getDefines($strict ? ['state' => ModuleDefine::STATE_ENABLED] : []); $defines = dcCore::app()->plugins->getDefines($strict ? ['state' => dcModuleDefine::STATE_ENABLED] : []);
foreach ($defines as $define) { foreach ($defines as $define) {
if ($strict && in_array($define->getId(), $hiddens)) { if ($strict && in_array($define->getId(), $hiddens)) {
continue; continue;
} }
$modules[(string) $define->getId()] = (string) $define->get('version'); $modules[$define->getId()] = $define->get('version');
} }
return $modules; return $modules;
@ -106,48 +108,24 @@ class Utils
*/ */
public static function getThemes(bool $strict = true): array public static function getThemes(bool $strict = true): array
{ {
if (App::themes()->isEmpty()) { if (!(dcCore::app()->themes instanceof dcThemes)) {
App::themes()->loadModules(App::blog()->themesPath()); dcCore::app()->themes = new dcThemes();
dcCore::app()->themes->loadModules(dcCore::app()->blog->themes_path);
} }
$modules = []; $modules = [];
$hiddens = self::getHiddens(); $hiddens = self::getHiddens();
$defines = App::themes()->getDefines($strict ? ['state' => ModuleDefine::STATE_ENABLED] : []); $defines = dcCore::app()->themes->getDefines($strict ? ['state' => dcModuleDefine::STATE_ENABLED] : []);
foreach ($defines as $define) { foreach ($defines as $define) {
if ($strict && in_array($define->getId(), $hiddens)) { if ($strict && in_array($define->getId(), $hiddens)) {
continue; continue;
} }
$modules[(string) $define->getId()] = (string) $define->get('version'); $modules[$define->getId()] = $define->get('version');
} }
return $modules; return $modules;
} }
/**
* Get server software and version.
*
* @return array<string,string> The server info
*/
public static function getServer(): array
{
$res = [
'name' => 'undefined',
'version' => 'undefined',
];
if (!empty($_SERVER['SERVER_SOFTWARE'])) {
$exp = explode('/', $_SERVER['SERVER_SOFTWARE']);
if (count($exp) == 2) {
$res = [
'name' => $exp[0],
'version' => $exp[1],
];
}
}
return $res;
}
/** /**
* Get report contents. * Get report contents.
* *
@ -171,7 +149,7 @@ class Utils
*/ */
public static function getError(): string public static function getError(): string
{ {
$rs = App::log()->getLogs([ $rs = dcCore::app()->log->getLogs([
'log_table' => My::id() . '_error', 'log_table' => My::id() . '_error',
]); ]);
@ -255,24 +233,14 @@ class Utils
} }
} }
/**
* Check if report can be done.
*
* @return bool True if it can
*/
private static function check(): bool private static function check(): bool
{ {
return true; // not yet return defined('DC_CRYPT_ALGO');
} }
/**
* Get report key.
*
* @return string The report key
*/
private static function key(): string private static function key(): string
{ {
return Crypt::hmac(self::uid() . My::id(), App::config()->cryptAlgo()); return Crypt::hmac(self::uid() . My::id(), DC_CRYPT_ALGO);
} }
private static function uid(): string private static function uid(): string
@ -288,21 +256,11 @@ class Utils
return self::$uid; return self::$uid;
} }
/**
* Get blog report uid.
*
* @return string The blog report uid
*/
private static function buid(): string private static function buid(): string
{ {
return md5(self::uid() . App::blog()->uid()); return md5(self::uid() . dcCore::app()->blog->uid);
} }
/**
* Get query URL.
*
* @return string The URL
*/
private static function url(): string private static function url(): string
{ {
$api_url = My::settings()->getGlobal('distant_api_url'); $api_url = My::settings()->getGlobal('distant_api_url');
@ -310,12 +268,9 @@ class Utils
return (is_string($api_url) ? $api_url : self::DISTANT_API_URL) . '/' . self::DISTANT_API_VERSION . '/%s/' . self::uid(); return (is_string($api_url) ? $api_url : self::DISTANT_API_URL) . '/' . self::DISTANT_API_VERSION . '/%s/' . self::uid();
} }
/**
* Clear report logs.
*/
private static function clear(): void private static function clear(): void
{ {
$rs = App::log()->getLogs([ $rs = dcCore::app()->log->getLogs([
'log_table' => [ 'log_table' => [
My::id() . '_report', My::id() . '_report',
My::id() . '_error', My::id() . '_error',
@ -330,56 +285,49 @@ class Utils
while ($rs->fetch()) { while ($rs->fetch()) {
$logs[] = (int) $rs->f('log_id'); $logs[] = (int) $rs->f('log_id');
} }
App::log()->delLogs($logs); dcCore::app()->log->delLogs($logs);
} }
/**
* Log error.
*/
private static function error(string $message): void private static function error(string $message): void
{ {
self::clear(); self::clear();
$cur = App::log()->openLogCursor(); $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME);
$cur->setField('log_table', My::id() . '_error'); $cur->setField('log_table', My::id() . '_error');
$cur->setField('log_msg', $message); $cur->setField('log_msg', $message);
App::log()->addLog($cur); dcCore::app()->log->addLog($cur);
} }
/**
* Write report.
*/
private static function write(string $contents): void private static function write(string $contents): void
{ {
self::clear(); self::clear();
$cur = App::log()->openLogCursor(); $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME);
$cur->setField('log_table', My::id() . '_report'); $cur->setField('log_table', My::id() . '_report');
$cur->setField('log_msg', $contents); $cur->setField('log_msg', $contents);
App::log()->addLog($cur); dcCore::app()->log->addLog($cur);
} }
/** private static function read(): string
* Check if report is expired.
*
* @return bool True if expired
*/
private static function expired(): bool
{ {
$rs = App::log()->getLogs([ $rs = dcCore::app()->log->getLogs([
'log_table' => My::id() . '_report', 'log_table' => My::id() . '_report',
]); ]);
return $rs->isEmpty() || !is_string($rs->f('log_dt')) || (int) strtotime($rs->f('log_dt')) + self::EXPIRED_DELAY < time(); return $rs->isEmpty() || !is_string($rs->f('log_msg')) ? '' : $rs->f('log_msg');
}
private static function expired(): bool
{
$rs = dcCore::app()->log->getLogs([
'log_table' => My::id() . '_report',
]);
return $rs->isEmpty() || !is_string($rs->f('log_dt')) || (int) Date::str('%s', $rs->f('log_dt')) + self::EXPIRED_DELAY < time();
} }
/**
* Get report content.
*
* @return string Teh report content
*/
private static function contents(): string private static function contents(): string
{ {
// Build json response // Build json response
@ -389,28 +337,26 @@ class Utils
'plugins' => self::getPlugins(), // enabled plugins 'plugins' => self::getPlugins(), // enabled plugins
'themes' => self::getThemes(), // enabled themes 'themes' => self::getThemes(), // enabled themes
'blog' => [ 'blog' => [
'lang' => (string) App::blog()->settings()->get('system')->get('lang'), 'lang' => (string) dcCore::app()->blog->settings->get('system')->get('lang'),
'theme' => (string) App::blog()->settings()->get('system')->get('theme'), 'theme' => (string) dcCore::app()->blog->settings->get('system')->get('theme'),
], ],
'blogs' => [ 'blogs' => [
'count' => (int) App::blogs()->getBlogs([], true)->f(0), 'count' => (int) dcCore::app()->getBlogs([], true)->f(0),
], ],
'core' => [ 'core' => [
'version' => App::config()->dotclearVersion(), 'version' => DC_VERSION,
], ],
'server' => self::getServer(), 'php' => [
'php' => [
'sapi' => php_sapi_name() ?: 'php', 'sapi' => php_sapi_name() ?: 'php',
'version' => PHP_VERSION, 'version' => phpversion(),
'minor' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION,
], ],
'system' => [ 'system' => [
'name' => php_uname('s'), 'name' => php_uname('s'),
'version' => php_uname('r'), 'version' => php_uname('r'),
], ],
'database' => [ 'database' => [
'driver' => App::con()->driver(), 'driver' => dcCore::app()->con->driver(),
'version' => App::con()->version(), 'version' => dcCore::app()->con->version(),
], ],
], JSON_PRETTY_PRINT); ], JSON_PRETTY_PRINT);
} }