Compare commits

...

1 Commits
v3.4 ... master

Author SHA1 Message Date
Jean-Christian Paul Denis 15eb8f7676
Code review 2023-10-24 22:55:12 +02:00
16 changed files with 392 additions and 256 deletions

View File

@ -1,3 +1,9 @@
activityReport 3.4.1 - 2023.10.24
===========================================================
* Require Dotclear 2.28
* Require PHP 8.1
* Code review
activityReport 3.4 - 2023.10.18 activityReport 3.4 - 2023.10.18
=========================================================== ===========================================================
* Require Dotclear 2.28 * Require Dotclear 2.28

View File

@ -1,7 +1,7 @@
# README # README
[![Release](https://img.shields.io/badge/release-3.4-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/activityReport/releases) [![Release](https://img.shields.io/badge/release-3.4.1-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/activityReport/releases)
![Date](https://img.shields.io/badge/date-2023.10.18-c44d58.svg) ![Date](https://img.shields.io/badge/date-2023.10.24-c44d58.svg)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download) [![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download)
[![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/activityReport) [![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/activityReport)
[![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/activityReport/src/branch/master/LICENSE) [![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/activityReport/src/branch/master/LICENSE)
@ -17,7 +17,7 @@ _activityReport_ is a plugin for the open-source web publishing software called
* Dotclear 2.28 * Dotclear 2.28
* PHP 8.1+ * PHP 8.1+
* System permissions to add table on database * System permissions to add table on database
* System permissions to send email * System permissions to send email (optionnal)
* Dotclear admin permissions * Dotclear admin permissions
## USAGE ## USAGE
@ -37,6 +37,7 @@ Once it's done you can manage your reports from menu
* [Packages & details](https://git.dotclear.watch/JcDenis/activityReport/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/activityReport)) * [Packages & details](https://git.dotclear.watch/JcDenis/activityReport/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/activityReport))
* [Sources & contributions](https://git.dotclear.watch/JcDenis/activityReport) (or on [GitHub](https://github.com/JcDenis/activityReport)) * [Sources & contributions](https://git.dotclear.watch/JcDenis/activityReport) (or on [GitHub](https://github.com/JcDenis/activityReport))
* [Issues & security](https://git.dotclear.watch/JcDenis/activityReport/issues) (or on [GitHub](https://github.com/JcDenis/activityReport/issues)) * [Issues & security](https://git.dotclear.watch/JcDenis/activityReport/issues) (or on [GitHub](https://github.com/JcDenis/activityReport/issues))
* [Discuss & help](https://forum.dotclear.org/viewtopic.php?id=40504)
## CONTRIBUTORS ## CONTRIBUTORS

View File

@ -17,7 +17,7 @@ $this->registerModule(
'Activity log', 'Activity log',
'Log and receive your blog activity by email, feed, or on dashboard', 'Log and receive your blog activity by email, feed, or on dashboard',
'Jean-Christian Denis and contributors', 'Jean-Christian Denis and contributors',
'3.4', '3.4.1',
[ [
'requires' => [['core', '2.28']], 'requires' => [['core', '2.28']],
'permissions' => 'My', 'permissions' => 'My',

View File

@ -2,10 +2,10 @@
<modules xmlns:da="http://dotaddict.org/da/"> <modules xmlns:da="http://dotaddict.org/da/">
<module id="activityReport"> <module id="activityReport">
<name>Activity log</name> <name>Activity log</name>
<version>3.4</version> <version>3.4.1</version>
<author>Jean-Christian Denis and contributors</author> <author>Jean-Christian Denis and contributors</author>
<desc>Log and receive your blog activity by email, feed, or on dashboard</desc> <desc>Log and receive your blog activity by email, feed, or on dashboard</desc>
<file>https://git.dotclear.watch/JcDenis/activityReport/releases/download/v3.4/plugin-activityReport.zip</file> <file>https://git.dotclear.watch/JcDenis/activityReport/releases/download/v3.4.1/plugin-activityReport.zip</file>
<da:dcmin>2.28</da:dcmin> <da:dcmin>2.28</da:dcmin>
<da:details>https://git.dotclear.watch/JcDenis/activityReport/src/branch/master/README.md</da:details> <da:details>https://git.dotclear.watch/JcDenis/activityReport/src/branch/master/README.md</da:details>
<da:support>https://git.dotclear.watch/JcDenis/activityReport/issues</da:support> <da:support>https://git.dotclear.watch/JcDenis/activityReport/issues</da:support>

View File

@ -41,28 +41,60 @@ class ActivityReport
*/ */
public const ACTIVITYREPORT_CLASS_NAME = 'ActivityReportAction'; public const ACTIVITYREPORT_CLASS_NAME = 'ActivityReportAction';
/** @var int activity marked as pending mail report */ /**
* Activity marked as pending mail report.
*
* @var int STATUS_PENDING
*/
public const STATUS_PENDING = 0; public const STATUS_PENDING = 0;
/** @var int activity marked as reported by mail */ /**
* Activity marked as reported by mail.
*
* @var int STATUS_REPORTED
*/
public const STATUS_REPORTED = 1; public const STATUS_REPORTED = 1;
/** @var string $type Activity report type (by default activityReport) */ /**
* Activity report type (by default activityReport).
*
* @var string $type
*/
public readonly string $type; public readonly string $type;
/** @var Settings $settings Activity report settings for current blog */ /**
* Activity report settings for current blog.
*
* @var Settings $settings
*/
public readonly Settings $settings; public readonly Settings $settings;
/** @var Groups $groups Groups of actions */ /**
* Groups of actions.
*
* @var Groups $groups
*/
public readonly Groups $groups; public readonly Groups $groups;
/** @var Formats $formats Export available formats */ /**
* Export available formats.
*
* @var Formats $formats
*/
public readonly Formats $formats; public readonly Formats $formats;
/** @var ActivityReport $instance ActivityReport instance */ /**
* ActivityReport instance.
*
* @var ActivityReport $instance
*/
private static $instance; private static $instance;
/** @var null|string $lock File lock for update */ /**
* File lock for update.
*
* @var null|string $lock
*/
private static $lock = null; private static $lock = null;
/** /**
@ -115,13 +147,13 @@ class ActivityReport
/** /**
* Get logs record. * Get logs record.
* *
* @param null|ArrayObject $params The query params * @param null|ArrayObject<string, mixed> $params The query params
* @param bool $count_only Count only * @param bool $count_only Count only
* @param null|SelectStatement $ext_sql The sql select statement * @param null|SelectStatement $ext_sql The sql select statement
* *
* @return null|MetaRecord The logs record * @return MetaRecord The logs record
*/ */
public function getLogs(ArrayObject $params = null, bool $count_only = false, ?SelectStatement $ext_sql = null): ?MetaRecord public function getLogs(ArrayObject $params = null, bool $count_only = false, ?SelectStatement $ext_sql = null): MetaRecord
{ {
if (is_null($params)) { if (is_null($params)) {
$params = new ArrayObject(); $params = new ArrayObject();
@ -179,7 +211,7 @@ class ActivityReport
$sql->where('E.activity_type = ' . $sql->quote($this->type)); $sql->where('E.activity_type = ' . $sql->quote($this->type));
} }
if (isset($params['blog_id']) && is_null($params['blog_id'])) { if (isset($params['blog_id']) && $params['blog_id'] != '') {
$sql->and('E.blog_id IS NOT NULL'); $sql->and('E.blog_id IS NOT NULL');
} elseif (!empty($params['blog_id'])) { } elseif (!empty($params['blog_id'])) {
if (!is_array($params['blog_id'])) { if (!is_array($params['blog_id'])) {
@ -243,9 +275,10 @@ class ActivityReport
if (!$count_only && !empty($params['limit'])) { if (!$count_only && !empty($params['limit'])) {
$sql->limit($params['limit']); $sql->limit($params['limit']);
} }
$rs = $sql->select(); $rs = $sql->select();
return $sql->select(); return is_null($rs) ? MetaRecord::newFromArray([]) : $rs;
} }
/** /**
@ -253,7 +286,7 @@ class ActivityReport
* *
* @param string $group The group * @param string $group The group
* @param string $action The action * @param string $action The action
* @param array<int,string> $logs The logs values * @param array<int, string> $logs The logs values
*/ */
public function addLog(string $group, string $action, array $logs): void public function addLog(string $group, string $action, array $logs): void
{ {
@ -616,7 +649,7 @@ class ActivityReport
]); ]);
$logs = $this->getLogs($params); $logs = $this->getLogs($params);
if (!is_null($logs) && !$logs->isEmpty()) { if (!$logs->isEmpty()) {
// Datas to readable text // Datas to readable text
$content = $this->parseLogs($logs); $content = $this->parseLogs($logs);
if (!empty($content)) { if (!empty($content)) {

View File

@ -330,6 +330,9 @@ class ActivityReportAction extends Process
ActivityReport::instance()->addLog('post', 'delete', $logs); ActivityReport::instance()->addLog('post', 'delete', $logs);
} }
/**
* @param ArrayObject<string, mixed> $result
*/
public static function postPasswordAttempt(ArrayObject $result): void public static function postPasswordAttempt(ArrayObject $result): void
{ {
if ($result['tpl'] != 'password-form.html' || empty($_POST['password'])) { if ($result['tpl'] != 'password-form.html' || empty($_POST['password'])) {

View File

@ -4,18 +4,8 @@ declare(strict_types=1);
namespace Dotclear\Plugin\activityReport; namespace Dotclear\Plugin\activityReport;
use ArrayObject;
use Dotclear\App; use Dotclear\App;
use Dotclear\Core\Backend\Favorites;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Div,
Label,
Para,
Select,
Text
};
/** /**
* @brief activityReport backend class. * @brief activityReport backend class.
@ -33,142 +23,22 @@ class Backend extends Process
public static function process(): bool public static function process(): bool
{ {
if (!self::status()) { if (self::status()) {
return false;
}
// be sure to init report // be sure to init report
ActivityReport::init(); ActivityReport::init();
My::addBackendMenuItem(); My::addBackendMenuItem();
App::behavior()->addBehaviors([ App::behavior()->addBehaviors([
// dashboard favorites icon 'adminDashboardFavoritesV2' => BackendBehaviors::adminDashboardFavoritesV2(...),
'adminDashboardFavoritesV2' => function (Favorites $favs): void { 'adminDashboardContentsV2' => BackendBehaviors::adminDashboardContentsV2(...),
$favs->register(My::id(), [ 'adminDashboardOptionsFormV2' => BackendBehaviors::adminDashboardOptionsFormV2(...),
'title' => My::name(), 'adminAfterDashboardOptionsUpdate' => BackendBehaviors::adminAfterDashboardOptionsUpdate(...),
'url' => My::manageUrl(), 'adminFiltersListsV2' => BackendBehaviors::adminFiltersListsV2(...),
'small-icon' => My::icons(), 'adminColumnsListsV2' => BackendBehaviors::adminColumnsListsV2(...),
'large-icon' => My::icons(),
'permissions' => App::auth()->makePermissions([
App::auth()::PERMISSION_ADMIN,
]),
]); ]);
},
// dashboard content display
'adminDashboardContentsV2' => function (ArrayObject $items): void {
$db = App::auth()->prefs()->get(My::id())->get('dashboard_item');
$limit = abs(is_numeric($db) ? (int) $db : 0);
if (!$limit) {
return ;
} }
$params = new ArrayObject([ return self::status();
'limit' => $limit,
'requests' => true,
]);
$rs = ActivityReport::instance()->getLogs($params);
if (!$rs || $rs->isEmpty()) {
return;
}
$lines = [];
$groups = ActivityReport::instance()->groups;
while ($rs->fetch()) {
$row = new ActivityRow($rs);
if (!$groups->has($row->group)) {
continue;
}
$group = $groups->get($row->group);
$lines[] = '<dt title="' . __($group->title) . '">' .
'<strong>' . __($group->get($row->action)->title) . '</strong>' .
'<br />' . Date::str(
App::blog()->settings()->get('system')->get('date_format') . ', ' . App::blog()->settings()->get('system')->get('time_format'),
(int) strtotime($row->dt),
is_string(App::auth()->getInfo('user_tz')) ? App::auth()->getInfo('user_tz') : 'UTC'
) . '<dt>' .
'<dd><p>' .
'<em>' . ActivityReport::parseMessage(__($group->get($row->action)->message), $row->logs) . '</em></p></dd>';
}
if (empty($lines)) {
return ;
}
$items[] = new ArrayObject([
'<div id="activity-report-logs" class="box medium">' .
'<h3>' . My::name() . '</h3>' .
'<dl id="reports">' . implode('', $lines) . '</dl>' .
'<p class="modules"><a class="module-details" href="' .
My::manageUrl() . '">' .
__('View all logs') . '</a> - <a class="module-config" href="' .
App::backend()->url()->get('admin.plugins', [
'module' => My::id(),
'conf' => 1,
'redir' => App::backend()->url()->get('admin.home'),
]) . '">' .
__('Configure plugin') . '</a></p>' .
'</div>',
]);
},
// dashboard content user preference form
'adminDashboardOptionsFormV2' => function (): void {
$db = App::auth()->prefs()->get(My::id())->get('dashboard_item');
echo
(new Div())->class('fieldset')->items([
(new Text('h4', My::name())),
(new Para())->items([
(new Label(__('Number of activities to show on dashboard:'), Label::OUTSIDE_LABEL_BEFORE))->for(My::id() . '_dashboard_item'),
(new Select(My::id() . '_dashboard_item'))->default(is_string($db) ? $db : '')->items([
__('Do not show activity report') => 0,
5 => 5,
10 => 10,
15 => 15,
20 => 20,
50 => 50,
100 => 100,
]),
]),
])->render();
},
// save dashboard content user preference
'adminAfterDashboardOptionsUpdate' => function (?string $user_id = null): void {
if (!is_null($user_id)) {
App::auth()->prefs()->get(My::id())->put(
'dashboard_item',
(int) $_POST[My::id() . '_dashboard_item'],
'integer'
);
}
},
// list filters
'adminFiltersListsV2' => function (ArrayObject $sorts): void {
$sorts[My::id()] = [
My::name(),
[
__('Group') => 'activity_group',
__('Action') => 'activity_action',
__('Date') => 'activity_dt',
__('Status') => 'activity_status',
],
'activity_dt',
'desc',
[__('logs per page'), 30],
];
},
// list columns user preference
'adminColumnsListsV2' => function (ArrayObject $cols): void {
$cols[My::id()] = [
My::name(),
[
'activity_group' => [true, __('Group')],
'activity_action' => [true, __('Action')],
'activity_dt' => [true, __('Date')],
'activity_status' => [false, __('Status')],
],
];
},
]);
return true;
} }
} }

View File

@ -0,0 +1,181 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\activityReport;
use ArrayObject;
use Dotclear\App;
use Dotclear\Core\Backend\Favorites;
use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Div,
Label,
Para,
Select,
Text
};
/**
* @brief activityReport backend behaviors class.
* @ingroup activityReport
*
* @author Jean-Christian Denis (author)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class BackendBehaviors
{
/**
* Dashboard favorites icon.
*/
public static function adminDashboardFavoritesV2(Favorites $favs): void
{
$favs->register(My::id(), [
'title' => My::name(),
'url' => My::manageUrl(),
'small-icon' => My::icons(),
'large-icon' => My::icons(),
'permissions' => App::auth()->makePermissions([
App::auth()::PERMISSION_ADMIN,
]),
]);
}
/**
* Dashboard content display.
*
* @param ArrayObject<int, mixed> $items
*/
public static function adminDashboardContentsV2(ArrayObject $items): void
{
$db = App::auth()->prefs()->get(My::id())->get('dashboard_item');
$limit = abs(is_numeric($db) ? (int) $db : 0);
if (!$limit) {
return ;
}
$params = new ArrayObject([
'limit' => $limit,
'requests' => true,
]);
$rs = ActivityReport::instance()->getLogs($params);
if ($rs->isEmpty()) {
return;
}
$lines = [];
$groups = ActivityReport::instance()->groups;
while ($rs->fetch()) {
$row = new ActivityRow($rs);
if (!$groups->has($row->group)) {
continue;
}
$group = $groups->get($row->group);
$lines[] = '<dt title="' . __($group->title) . '">' .
'<strong>' . __($group->get($row->action)->title) . '</strong>' .
'<br />' . Date::str(
App::blog()->settings()->get('system')->get('date_format') . ', ' . App::blog()->settings()->get('system')->get('time_format'),
(int) strtotime($row->dt),
is_string(App::auth()->getInfo('user_tz')) ? App::auth()->getInfo('user_tz') : 'UTC'
) . '<dt>' .
'<dd><p>' .
'<em>' . ActivityReport::parseMessage(__($group->get($row->action)->message), $row->logs) . '</em></p></dd>';
}
if (empty($lines)) {
return ;
}
$items[] = new ArrayObject([
'<div id="activity-report-logs" class="box medium">' .
'<h3>' . My::name() . '</h3>' .
'<dl id="reports">' . implode('', $lines) . '</dl>' .
'<p class="modules"><a class="module-details" href="' .
My::manageUrl() . '">' .
__('View all logs') . '</a> - <a class="module-config" href="' .
App::backend()->url()->get('admin.plugins', [
'module' => My::id(),
'conf' => 1,
'redir' => App::backend()->url()->get('admin.home'),
]) . '">' .
__('Configure plugin') . '</a></p>' .
'</div>',
]);
}
/**
* Dashboard content user preference form.
*/
public static function adminDashboardOptionsFormV2(): void
{
$db = App::auth()->prefs()->get(My::id())->get('dashboard_item');
echo
(new Div())->class('fieldset')->items([
(new Text('h4', My::name())),
(new Para())->items([
(new Label(__('Number of activities to show on dashboard:'), Label::OUTSIDE_LABEL_BEFORE))->for(My::id() . '_dashboard_item'),
(new Select(My::id() . '_dashboard_item'))->default(is_string($db) ? $db : '')->items([
__('Do not show activity report') => 0,
5 => 5,
10 => 10,
15 => 15,
20 => 20,
50 => 50,
100 => 100,
]),
]),
])->render();
}
/**
* Save dashboard content user preference.
*/
public static function adminAfterDashboardOptionsUpdate(?string $user_id = null): void
{
if (!is_null($user_id)) {
App::auth()->prefs()->get(My::id())->put(
'dashboard_item',
(int) $_POST[My::id() . '_dashboard_item'],
'integer'
);
}
}
/**
* List filters.
*
* @param ArrayObject<string, mixed> $sorts
*/
public static function adminFiltersListsV2(ArrayObject $sorts): void
{
$sorts[My::id()] = [
My::name(),
[
__('Group') => 'activity_group',
__('Action') => 'activity_action',
__('Date') => 'activity_dt',
__('Status') => 'activity_status',
],
'activity_dt',
'desc',
[__('logs per page'), 30],
];
}
/**
* List columns user preference.
*
* @param ArrayObject<string, mixed> $cols
*/
public static function adminColumnsListsV2(ArrayObject $cols): void
{
$cols[My::id()] = [
My::name(),
[
'activity_group' => [true, __('Group')],
'activity_action' => [true, __('Action')],
'activity_dt' => [true, __('Date')],
'activity_status' => [false, __('Status')],
],
];
}
}

View File

@ -131,13 +131,13 @@ class Config extends Process
]), ]),
(new Para())->items([ (new Para())->items([
(new Label(__('Recipients:'), Label::OUTSIDE_LABEL_BEFORE))->for('mailinglist'), (new Label(__('Recipients:'), Label::OUTSIDE_LABEL_BEFORE))->for('mailinglist'),
(new Input('mailinglist'))->size(60)->maxlenght(255)->value(implode(';', $s->mailinglist)), (new Input('mailinglist'))->size(60)->maxlength(255)->value(implode(';', $s->mailinglist)),
]), ]),
(new Note())->class('form-note')->text(__('Separate multiple email addresses with a semicolon ";"')), (new Note())->class('form-note')->text(__('Separate multiple email addresses with a semicolon ";"')),
(new Note())->class('form-note')->text(__('Leave it empty to disable mail report.')), (new Note())->class('form-note')->text(__('Leave it empty to disable mail report.')),
(new Para())->items([ (new Para())->items([
(new Label(__('Date format:'), Label::OUTSIDE_LABEL_BEFORE))->for('dateformat'), (new Label(__('Date format:'), Label::OUTSIDE_LABEL_BEFORE))->for('dateformat'),
(new Input('dateformat'))->size(60)->maxlenght(255)->value($s->dateformat), (new Input('dateformat'))->size(60)->maxlength(255)->value($s->dateformat),
]), ]),
(new Note())->class('form-note')->text(__('Use Dotclear date formaters. ex: %B %d at %H:%M')), (new Note())->class('form-note')->text(__('Use Dotclear date formaters. ex: %B %d at %H:%M')),
(new Para())->items([ (new Para())->items([

View File

@ -23,21 +23,19 @@ class Frontend extends Process
public static function process(): bool public static function process(): bool
{ {
if (!self::status()) { if (self::status()) {
return false;
}
// be sure to init report // be sure to init report
ActivityReport::init(); ActivityReport::init();
App::frontend()->template()->setPath(App::frontend()->template()->getPath(), implode(DIRECTORY_SEPARATOR, [My::path(), 'default-templates', 'tpl'])); $tpl = App::frontend()->template();
$tpl->setPath($tpl->getPath(), implode(DIRECTORY_SEPARATOR, [My::path(), 'default-templates', 'tpl']));
$tpl->addBlock('activityReports', FrontendTemplate::activityReports(...));
$tpl->addValue('activityReportFeedID', FrontendTemplate::activityReportFeedID(...));
$tpl->addValue('activityReportTitle', FrontendTemplate::activityReportTitle(...));
$tpl->addValue('activityReportDate', FrontendTemplate::activityReportDate(...));
$tpl->addValue('activityReportContent', FrontendTemplate::activityReportContent(...));
}
App::frontend()->template()->addBlock('activityReports', Template::activityReports(...)); return self::status();
App::frontend()->template()->addValue('activityReportFeedID', Template::activityReportFeedID(...));
App::frontend()->template()->addValue('activityReportTitle', Template::activityReportTitle(...));
App::frontend()->template()->addValue('activityReportDate', Template::activityReportDate(...));
App::frontend()->template()->addValue('activityReportContent', Template::activityReportContent(...));
return true;
} }
} }

View File

@ -14,7 +14,7 @@ use Dotclear\Database\MetaRecord;
* @author Jean-Christian Denis (author) * @author Jean-Christian Denis (author)
* @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
*/ */
class Context class FrontendContext
{ {
/** /**
* Parse title. * Parse title.

View File

@ -15,7 +15,7 @@ use Dotclear\Helper\Date;
* @author Jean-Christian Denis (author) * @author Jean-Christian Denis (author)
* @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
*/ */
class Template class FrontendTemplate
{ {
/** /**
* tpl:activityReports [attributes] : Activity report logs (tpl block) * tpl:activityReports [attributes] : Activity report logs (tpl block)
@ -25,7 +25,7 @@ class Template
* - lastn integer Limit to last n logs * - lastn integer Limit to last n logs
* - ingnore_pagination 1|0 Ignore pagination paramaters * - ingnore_pagination 1|0 Ignore pagination paramaters
* *
* @param ArrayObject $attr The attributes * @param ArrayObject<string, mixed> $attr The attributes
* @param string $content The content * @param string $content The content
* *
* @return string The code * @return string The code
@ -37,7 +37,7 @@ class Template
$lastn = abs((int) $attr['lastn']) + 0; $lastn = abs((int) $attr['lastn']) + 0;
} }
$p = '$_page_number = App::frontend()->getPageNumber(); if ($_page_number < 1) { $_page_number = 1; }' . "\n\$params = new ArrayObject();\n"; $p = '$page_number = App::frontend()->getPageNumber(); if ($page_number < 1) { $page_number = 1; }' . "\n\$params = new ArrayObject();\n";
if ($lastn > 0) { if ($lastn > 0) {
$p .= "\$params['limit'] = " . $lastn . ";\n"; $p .= "\$params['limit'] = " . $lastn . ";\n";
@ -46,7 +46,7 @@ class Template
} }
if (!isset($attr['ignore_pagination']) || $attr['ignore_pagination'] == '0') { if (!isset($attr['ignore_pagination']) || $attr['ignore_pagination'] == '0') {
$p .= "\$params['limit'] = array(((\$_page_number-1)*\$params['limit']),\$params['limit']);\n"; $p .= "\$params['limit'] = array(((\$page_number-1)*\$params['limit']),\$params['limit']);\n";
} else { } else {
$p .= "\$params['limit'] = array(0, \$params['limit']);\n"; $p .= "\$params['limit'] = array(0, \$params['limit']);\n";
} }
@ -68,7 +68,7 @@ class Template
* *
* - any filters See self::getFilters() * - any filters See self::getFilters()
* *
* @param ArrayObject $attr The attributes * @param ArrayObject<string, mixed> $attr The attributes
* *
* @return string The code * @return string The code
*/ */
@ -87,7 +87,7 @@ class Template
* *
* - any filters See self::getFilters() * - any filters See self::getFilters()
* *
* @param ArrayObject $attr The attributes * @param ArrayObject<string, mixed> $attr The attributes
* *
* @return string The code * @return string The code
*/ */
@ -95,7 +95,7 @@ class Template
{ {
$f = App::frontend()->template()->getFilters($attr); $f = App::frontend()->template()->getFilters($attr);
return '<?php echo ' . sprintf($f, Context::class . '::parseTitle()') . '; ?>'; return '<?php echo ' . sprintf($f, FrontendContext::class . '::parseTitle()') . '; ?>';
} }
/** /**
@ -105,7 +105,7 @@ class Template
* *
* - any filters See self::getFilters() * - any filters See self::getFilters()
* *
* @param ArrayObject $attr The attributes * @param ArrayObject<string, mixed> $attr The attributes
* *
* @return string The code * @return string The code
*/ */
@ -113,7 +113,7 @@ class Template
{ {
$f = App::frontend()->template()->getFilters($attr); $f = App::frontend()->template()->getFilters($attr);
return '<?php echo ' . sprintf($f, Context::class . '::parseContent()') . '; ?>'; return '<?php echo ' . sprintf($f, FrontendContext::class . '::parseContent()') . '; ?>';
} }
/** /**
@ -126,7 +126,7 @@ class Template
* - rfc822 (1|0) Use Date::rfc822() * - rfc822 (1|0) Use Date::rfc822()
* - any filters See self::getFilters() * - any filters See self::getFilters()
* *
* @param ArrayObject $attr The attributes * @param ArrayObject<string, mixed> $attr The attributes
* *
* @return string The code * @return string The code
*/ */

View File

@ -14,7 +14,7 @@ use Dotclear\Core\Frontend\Url;
* @author Jean-Christian Denis (author) * @author Jean-Christian Denis (author)
* @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
*/ */
class UrlHandler extends Url class FrontendUrl extends Url
{ {
/** /**
* Get activity logs feed. * Get activity logs feed.

View File

@ -6,7 +6,10 @@ namespace Dotclear\Plugin\activityReport;
use ArrayObject; use ArrayObject;
use Dotclear\App; use Dotclear\App;
use Dotclear\Core\Backend\Filter\Filters; use Dotclear\Core\Backend\Filter\{
Filters,
FiltersLibrary
};
use Dotclear\Core\Backend\{ use Dotclear\Core\Backend\{
Notices, Notices,
Page Page
@ -62,14 +65,13 @@ class Manage extends Process
$logs = $counter = $list = null; $logs = $counter = $list = null;
$filter = new Filters(My::id()); $filter = new Filters(My::id());
$filter->add(FiltersLibrary::getPageFilter());
$params = new ArrayObject($filter->params()); $params = new ArrayObject($filter->params());
try { try {
$logs = ActivityReport::instance()->getLogs($params); $logs = ActivityReport::instance()->getLogs($params);
$counter = ActivityReport::instance()->getLogs($params, true); $counter = ActivityReport::instance()->getLogs($params, true);
if (!is_null($logs) && !is_null($counter)) {
$list = new ManageList($logs, $counter->f(0)); $list = new ManageList($logs, $counter->f(0));
}
} catch (Exception $e) { } catch (Exception $e) {
App::error()->add($e->getMessage()); App::error()->add($e->getMessage());
} }

View File

@ -12,6 +12,18 @@ use Dotclear\Core\Backend\Listing\{
Pager Pager
}; };
use Dotclear\Helper\Date; use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Caption,
Div,
Note,
Table,
Tbody,
Td,
Text,
Th,
Tr
};
use Dotclear\Helper\Html\Html;
/** /**
* @brief activityReport manage logs list class. * @brief activityReport manage logs list class.
@ -25,50 +37,71 @@ class ManageList extends Listing
public function logsDisplay(Filters $filter, string $enclose_block = ''): void public function logsDisplay(Filters $filter, string $enclose_block = ''): void
{ {
if ($this->rs->isEmpty()) { if ($this->rs->isEmpty()) {
if ($filter->show()) { echo (new Note())
echo '<p><strong>' . __('No log matches the filter') . '</strong></p>'; ->text($filter->show() ? __('No log matches the filter') : __('No log'))
} else { ->class('info')
echo '<p><strong>' . __('No log') . '</strong></p>'; ->render();
return;
} }
} else {
$page = $filter->value('page'); $page = is_numeric($filter->value('page')) ? (int) $filter->value('page') : 1;
$nbpp = $filter->value('nb'); $nbpp = is_numeric($filter->value('nb')) ? (int) $filter->value('nb') : 20;
$pager = new Pager(is_numeric($page) ? (int) $page : 1, (int) $this->rs_count, is_numeric($nbpp) ? (int) $nbpp : 20, 10); $count = (int) $this->rs_count;
$pager = new Pager($page, $count, $nbpp, 10);
$pager->var_page = 'page'; $pager->var_page = 'page';
$html_block = '<div class="table-outer"><table><caption>' . (
$filter->show() ?
sprintf(__('List of %s logs matching the filter.'), $this->rs_count) :
sprintf(__('List of %s logs.'), $this->rs_count)
) . '</caption>';
$cols = new ArrayObject([ $cols = new ArrayObject([
'activity_group' => '<th scope="col" class="nowrap">' . __('Group') . '</th>', 'activity_group' => (new Th())
'activity_action' => '<th scope="col" class="nowrap">' . __('Action') . '</th>', ->text(__('Group'))
'activity_logs' => '<th scope="col" class="nowrap">' . __('Message') . '</th>', ->scope('col'),
'activity_date' => '<th scope="col" class="nowrap">' . __('Date') . '</th>', 'activity_action' => (new Th())
'activity_status' => '<th scope="col" class="nowrap">' . __('Status') . '</th>', ->text(__('Action'))
->scope('col'),
'activity_logs' => (new Th())
->text(__('Message'))
->scope('col'),
'activity_date' => (new Th())
->text(__('Date'))
->scope('col'),
'activity_status' => (new Th())
->text(__('Status'))
->scope('col'),
]); ]);
$this->userColumns(My::id(), $cols); $this->userColumns(My::id(), $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>'; $lines = [];
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) { while ($this->rs->fetch()) {
echo $this->logsLine(); $lines[] = $this->line();
} }
echo $blocks[1] . $blocks[2] . $pager->getLinks(); echo
} $pager->getLinks() .
sprintf(
$enclose_block,
(new Div())
->class('table-outer')
->items([
(new Table())
->items([
(new Caption(
$filter->show() ?
sprintf(__('List of %s logs matching the filter.'), $count) :
sprintf(__('List of logs. (%s)'), $count)
)),
(new Tr())
->items(iterator_to_array($cols)),
(new Tbody())
->items($lines),
]),
])
->render()
) .
$pager->getLinks();
} }
private function logsLine(): string private function line(): Tr
{ {
$row = new ActivityRow($this->rs); $row = new ActivityRow($this->rs);
@ -84,18 +117,27 @@ class ManageList extends Listing
$status = $row->status == ActivityReport::STATUS_PENDING ? __('pending') : __('reported'); $status = $row->status == ActivityReport::STATUS_PENDING ? __('pending') : __('reported');
$cols = new ArrayObject([ $cols = new ArrayObject([
'activity_group' => '<td class="nowrap">' . __($group->title) . '</td>', 'activity_group' => (new Td())
'activity_action' => '<td class="nowrap">' . __($action->title) . '</td>', ->text(Html::escapeHTML(__($group->title)))
'activity_logs' => '<td class="maximal">' . $message . '</td>', ->class('nowrap'),
'activity_date' => '<td class="nowrap">' . $date . '</td>', 'activity_action' => (new Td())
'activity_status' => '<td class="nowrap">' . $status . '</td>', ->text(Html::escapeHTML(__($action->title)))
->class('nowrap'),
'activity_logs' => (new Td())
->text(Html::escapeHTML($message))
->class('maximal'),
'activity_date' => (new Td())
->text(Html::escapeHTML($date))
->class('nowrap'),
'activity_status' => (new Td())
->text(Html::escapeHTML($status))
->class('nowrap'),
]); ]);
$this->userColumns(My::id(), $cols); $this->userColumns(My::id(), $cols);
return return (new Tr('l' . $row->id))
'<tr class="line ' . $offline . '" id="l' . $row->id . '">' . ->class('line' . $offline)
implode(iterator_to_array($cols)) . ->items(iterator_to_array($cols));
'</tr>';
} }
} }

View File

@ -32,7 +32,7 @@ class Prepend extends Process
My::id(), My::id(),
'reports', 'reports',
'^reports/((atom|rss2)/(.+))$', '^reports/((atom|rss2)/(.+))$',
UrlHandler::feed(...) FrontendUrl::feed(...)
); );
return true; return true;