Compare commits
10 Commits
8bcb572e28
...
90596323e1
Author | SHA1 | Date |
---|---|---|
Jean-Christian Paul Denis | 90596323e1 | |
Jean-Christian Paul Denis | ff58c0ba47 | |
Jean-Christian Paul Denis | 9f3108761c | |
Jean-Christian Paul Denis | 2a3a037e38 | |
Jean-Christian Paul Denis | 56552d12d3 | |
“philippe | 954f9ffb7f | |
“philippe | 2df4a4005e | |
“philippe | 90331d5159 | |
Jean-Christian Paul Denis | b1e0ecbc7f | |
Jean-Christian Paul Denis | da756d7625 |
|
@ -14,7 +14,7 @@ $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.3',
|
'0.5',
|
||||||
[
|
[
|
||||||
'requires' => [
|
'requires' => [
|
||||||
['php', '7.4'],
|
['php', '7.4'],
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<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.3</version>
|
<version>0.5</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://github.com/JcDenis/DotclearWatch/releases/download/v0.3/plugin-DotclearWatch.zip</file>
|
<file>https://github.com/JcDenis/DotclearWatch/releases/download/v0.5/plugin-DotclearWatch.zip</file>
|
||||||
<da:dcmin>2.27</da:dcmin>
|
<da:dcmin>2.27</da:dcmin>
|
||||||
<da:details>http://plugins.dotaddict.org/dc2/details/DotclearWatch</da:details>
|
<da:details>http://plugins.dotaddict.org/dc2/details/DotclearWatch</da:details>
|
||||||
<da:support>https://github.com/JcDenis/DotclearWatch/issues</da:support>
|
<da:support>https://github.com/JcDenis/DotclearWatch/issues</da:support>
|
||||||
|
|
|
@ -18,7 +18,7 @@ L10n::$locales['Settings are globals. Reports are by blog.']
|
||||||
L10n::$locales['Hidden modules:'] = 'Modules cachés :';
|
L10n::$locales['Hidden modules:'] = 'Modules cachés :';
|
||||||
L10n::$locales['This is the comma separated list of plugins IDs and themes IDs to ignore in report.'] = 'C\'est la liste des modules cachés séparés par une virgule.';
|
L10n::$locales['This is the comma separated list of plugins IDs and themes IDs to ignore in report.'] = 'C\'est la liste des modules cachés séparés par une virgule.';
|
||||||
L10n::$locales['Distant API URL:'] = 'URL de l\'API distante :';
|
L10n::$locales['Distant API URL:'] = 'URL de l\'API distante :';
|
||||||
L10n::$locales['This is the URL of the API to send report. Leave empty to reset value.'] = 'C\'est L\'URL de l\'API où sera envoyer le rapport. Laisser vide pour remettre par défaut.';
|
L10n::$locales['This is the URL of the API to send report. Leave empty to reset value.'] = 'C\'est L\'URL de l\'API où sera envoyé le rapport. Laisser vide pour remettre par défaut.';
|
||||||
L10n::$locales['Clear reports cache directory'] = 'Nettoyer le répertoire de cache des rapports.';
|
L10n::$locales['Clear reports cache directory'] = 'Nettoyer le répertoire de cache des rapports.';
|
||||||
L10n::$locales['This deletes all blogs reports in cache.'] = 'Ceci efface tous les rapports des blogs en cache.';
|
L10n::$locales['This deletes all blogs reports in cache.'] = 'Ceci efface tous les rapports des blogs en cache.';
|
||||||
L10n::$locales['Send report now'] = 'Envoyer le rapport maintenant';
|
L10n::$locales['Send report now'] = 'Envoyer le rapport maintenant';
|
||||||
|
|
|
@ -32,7 +32,7 @@ msgid "Distant API URL:"
|
||||||
msgstr "URL de l'API distante :"
|
msgstr "URL de l'API distante :"
|
||||||
|
|
||||||
msgid "This is the URL of the API to send report. Leave empty to reset value."
|
msgid "This is the URL of the API to send report. Leave empty to reset value."
|
||||||
msgstr "C'est L'URL de l'API où sera envoyer le rapport. Laisser vide pour remettre par défaut."
|
msgstr "C'est L'URL de l'API où sera envoyé le rapport. Laisser vide pour remettre par défaut."
|
||||||
|
|
||||||
msgid "Clear reports cache directory"
|
msgid "Clear reports cache directory"
|
||||||
msgstr "Nettoyer le répertoire de cache des rapports."
|
msgstr "Nettoyer le répertoire de cache des rapports."
|
||||||
|
|
|
@ -78,8 +78,13 @@ class Config extends Process
|
||||||
|
|
||||||
if (!empty($_POST['send_report'])) {
|
if (!empty($_POST['send_report'])) {
|
||||||
Utils::sendReport(true);
|
Utils::sendReport(true);
|
||||||
|
$error = Utils::getError();
|
||||||
|
if (!empty($error)) {
|
||||||
|
Notices::AddWarningNotice($error);
|
||||||
|
} else {
|
||||||
Notices::AddSuccessNotice(__('Report sent.'));
|
Notices::AddSuccessNotice(__('Report sent.'));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dcCore::app()->admin->url->redirect('admin.plugins', ['module' => My::id(), 'conf' => '1']);
|
dcCore::app()->admin->url->redirect('admin.plugins', ['module' => My::id(), 'conf' => '1']);
|
||||||
|
|
||||||
|
|
172
src/Utils.php
172
src/Utils.php
|
@ -15,11 +15,11 @@ declare(strict_types=1);
|
||||||
namespace Dotclear\Plugin\DotclearWatch;
|
namespace Dotclear\Plugin\DotclearWatch;
|
||||||
|
|
||||||
use dcCore;
|
use dcCore;
|
||||||
|
use dcLog;
|
||||||
use dcModuleDefine;
|
use dcModuleDefine;
|
||||||
use dcThemes;
|
use dcThemes;
|
||||||
use Dotclear\Helper\Crypt;
|
use Dotclear\Helper\Crypt;
|
||||||
use Dotclear\Helper\File\Files;
|
use Dotclear\Helper\Date;
|
||||||
use Dotclear\Helper\File\Path;
|
|
||||||
use Dotclear\Helper\Network\HttpClient;
|
use Dotclear\Helper\Network\HttpClient;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class Utils
|
||||||
public const DISTANT_API_URL = 'https://dotclear.watch/api';
|
public const DISTANT_API_URL = 'https://dotclear.watch/api';
|
||||||
|
|
||||||
/** @var string The distant API version */
|
/** @var string The distant API version */
|
||||||
public const DISTANT_API_VERSION = '1.0';
|
public const DISTANT_API_VERSION = '1.1';
|
||||||
|
|
||||||
/** @var array<int,string> The hiddens modules IDs */
|
/** @var array<int,string> The hiddens modules IDs */
|
||||||
private static array $hiddens = [];
|
private static array $hiddens = [];
|
||||||
|
@ -45,8 +45,14 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function addMark(): void
|
public static function addMark(): void
|
||||||
{
|
{
|
||||||
if (My::settings()->get('distant_api_url')) {
|
if (My::settings()->getGlobal('distant_api_url')) {
|
||||||
echo '<p>' . __('/!\ Tracked by dotclear.watch') . '</p>';
|
echo sprintf(
|
||||||
|
'<ul><li><a href="%s" title="%s" class="outgoing">%s<img src="%s" /></a></ul></li>',
|
||||||
|
'https://dotclear.watch/statistics',
|
||||||
|
__('DotclearWatch plugin statistics'),
|
||||||
|
__('Tracked by dotclear.watch'),
|
||||||
|
My::fileURL('icon.svg')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +144,18 @@ class Utils
|
||||||
return self::check() ? self::uid() : '';
|
return self::check() ? self::uid() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get request error.
|
||||||
|
*/
|
||||||
|
public static function getError(): string
|
||||||
|
{
|
||||||
|
$rs = dcCore::app()->log->getLogs([
|
||||||
|
'log_table' => My::id() . '_error',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $rs->isEmpty() || !is_string($rs->f('log_msg')) ? '' : $rs->f('log_msg');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear cache directory.
|
* Clear cache directory.
|
||||||
*/
|
*/
|
||||||
|
@ -162,31 +180,46 @@ class Utils
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = self::file();
|
if (!$force && !self::expired()) {
|
||||||
|
|
||||||
if (!$force && !self::expired($file)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contents = self::contents();
|
$contents = self::contents();
|
||||||
|
|
||||||
self::write($file, $contents);
|
self::write($contents);
|
||||||
|
|
||||||
|
$status = 500;
|
||||||
|
$response = '';
|
||||||
|
$url = sprintf(self::url(), 'report');
|
||||||
|
$path = '';
|
||||||
|
if ($client = HttpClient::initClient($url, $path)) {
|
||||||
try {
|
try {
|
||||||
$rsp = HttpClient::quickPost(sprintf(self::url(), 'report'), ['key' => self::key(), 'report' => $contents]);
|
$client->setUserAgent('Dotclear.watch ' . My::id() . '/' . self::DISTANT_API_VERSION);
|
||||||
if ($rsp !== 'ok') {
|
$client->useGzip(false);
|
||||||
throw new Exception('bad API response');
|
$client->setPersistReferers(false);
|
||||||
|
$client->post($path, ['key' => self::key(), 'report' => $contents]);
|
||||||
|
|
||||||
|
$status = $client->getStatus();
|
||||||
|
$response = $client->getContent();
|
||||||
|
unset($client);
|
||||||
|
if ($status != 202) {
|
||||||
|
self::error((string) '(' . $status . ') ' . $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
if ($force) {
|
unset($client);
|
||||||
dcCore::app()->error->add(__('Dotclear.watch report failed'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($force) {
|
||||||
|
self::error('Dotclear.watch report failed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function check(): bool
|
private static function check(): bool
|
||||||
{
|
{
|
||||||
return defined('DC_CRYPT_ALGO') && defined('DC_TPL_CACHE') && is_dir(DC_TPL_CACHE) && is_writable(DC_TPL_CACHE);
|
return defined('DC_CRYPT_ALGO');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function key(): string
|
private static function key(): string
|
||||||
|
@ -212,61 +245,71 @@ class Utils
|
||||||
return md5(self::uid() . dcCore::app()->blog->uid);
|
return md5(self::uid() . dcCore::app()->blog->uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function url()
|
private static function url(): string
|
||||||
{
|
{
|
||||||
$api_url = My::settings()->getGlobal('distant_api_url');
|
$api_url = My::settings()->getGlobal('distant_api_url');
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function file(): string
|
|
||||||
{
|
|
||||||
$file = self::buid();
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
'%s/%s/%s/%s/%s.json',
|
|
||||||
(string) Path::real(DC_TPL_CACHE),
|
|
||||||
My::id(),
|
|
||||||
substr($file, 0, 2),
|
|
||||||
substr($file, 2, 2),
|
|
||||||
$file
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function clear(): void
|
private static function clear(): void
|
||||||
{
|
{
|
||||||
$path = (string) Path::real(DC_TPL_CACHE) . DIRECTORY_SEPARATOR . My::id();
|
$rs = dcCore::app()->log->getLogs([
|
||||||
if (is_dir($path)) {
|
'log_table' => [
|
||||||
Files::delTree($path);
|
My::id() . '_report',
|
||||||
}
|
My::id() . '_error',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($rs->isEmpty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function write(string $file, string $contents): void
|
$logs = [];
|
||||||
|
while ($rs->fetch()) {
|
||||||
|
$logs[] = (int) $rs->f('log_id');
|
||||||
|
}
|
||||||
|
dcCore::app()->log->delLogs($logs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function error(string $message): void
|
||||||
{
|
{
|
||||||
$dir = dirname($file);
|
self::clear();
|
||||||
if (!is_dir($dir)) {
|
|
||||||
Files::makeDir($dir, true);
|
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME);
|
||||||
}
|
$cur->setField('log_table', My::id() . '_error');
|
||||||
file_put_contents($file, $contents);
|
$cur->setField('log_msg', $message);
|
||||||
|
|
||||||
|
dcCore::app()->log->addLog($cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function read(string $file): string
|
private static function write(string $contents): void
|
||||||
{
|
{
|
||||||
return is_file($file) && is_readable($file) ? (string) file_get_contents($file) : '';
|
self::clear();
|
||||||
|
|
||||||
|
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME);
|
||||||
|
$cur->setField('log_table', My::id() . '_report');
|
||||||
|
$cur->setField('log_msg', $contents);
|
||||||
|
|
||||||
|
dcCore::app()->log->addLog($cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function expired(string $file): bool
|
private static function read(): string
|
||||||
{
|
{
|
||||||
if (!is_file($file) || !is_readable($file) || ($time = filemtime($file)) === false) {
|
$rs = dcCore::app()->log->getLogs([
|
||||||
return true;
|
'log_table' => My::id() . '_report',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $rs->isEmpty() || !is_string($rs->f('log_msg')) ? '' : $rs->f('log_msg');
|
||||||
}
|
}
|
||||||
|
|
||||||
$time = date('U', $time);
|
private static function expired(): bool
|
||||||
if (!is_numeric($time) || (int) $time + self::EXPIRED_DELAY < time()) {
|
{
|
||||||
return true;
|
$rs = dcCore::app()->log->getLogs([
|
||||||
}
|
'log_table' => My::id() . '_report',
|
||||||
|
]);
|
||||||
|
|
||||||
return false;
|
return $rs->isEmpty() || !is_string($rs->f('log_dt')) || (int) Date::str('%s', $rs->f('log_dt')) + self::EXPIRED_DELAY < time();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function contents(): string
|
private static function contents(): string
|
||||||
|
@ -275,16 +318,29 @@ class Utils
|
||||||
return (string) json_encode([
|
return (string) json_encode([
|
||||||
'uid' => self::uid(),
|
'uid' => self::uid(),
|
||||||
'buid' => self::buid(),
|
'buid' => self::buid(),
|
||||||
'plugin' => self::getPlugins(), // enabled plugins
|
'plugins' => self::getPlugins(), // enabled plugins
|
||||||
'theme' => self::getThemes(), // enabled themes
|
'themes' => self::getThemes(), // enabled themes
|
||||||
'server' => [
|
'blog' => [
|
||||||
'blogs_count' => (int) dcCore::app()->getBlogs([], true)->f(0),
|
'lang' => (string) dcCore::app()->blog->settings->get('system')->get('lang'),
|
||||||
'core' => DC_VERSION,
|
'theme' => (string) dcCore::app()->blog->settings->get('system')->get('theme'),
|
||||||
'php' => phpversion(),
|
],
|
||||||
'thm' => (string) dcCore::app()->blog->settings->get('system')->get('theme'), // selected theme
|
'blogs' => [
|
||||||
|
'count' => (int) dcCore::app()->getBlogs([], true)->f(0),
|
||||||
|
],
|
||||||
|
'core' => [
|
||||||
|
'version' => DC_VERSION,
|
||||||
|
],
|
||||||
|
'php' => [
|
||||||
|
'sapi' => php_sapi_name() ?: 'php',
|
||||||
|
'version' => phpversion(),
|
||||||
|
],
|
||||||
|
'system' => [
|
||||||
|
'name' => php_uname('s'),
|
||||||
|
'version' => php_uname('r'),
|
||||||
],
|
],
|
||||||
'database' => [
|
'database' => [
|
||||||
dcCore::app()->con->driver() => dcCore::app()->con->version(),
|
'driver' => dcCore::app()->con->driver(),
|
||||||
|
'version' => dcCore::app()->con->version(),
|
||||||
],
|
],
|
||||||
], JSON_PRETTY_PRINT);
|
], JSON_PRETTY_PRINT);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue