Compare commits

..

No commits in common. "master" and "v1.3" have entirely different histories.
master ... v1.3

10 changed files with 172 additions and 144 deletions

View File

@ -1,9 +1,3 @@
topWriter 1.4 - 2023.10.20
===========================================================
* Require Dotclear 2.28
* Require PHP 8.1
* Upgrade to Dotclear 2.28
topWriter 1.3 - 2023.08.13
===========================================================
* Require Dotclear 2.27

View File

@ -1,22 +1,25 @@
# README
[![Release](https://img.shields.io/badge/release-1.4-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/topWriter/releases)
![Date](https://img.shields.io/badge/date-2023.10.20-c44d58.svg)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download)
[![Release](https://img.shields.io/badge/release-1.3-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/topWriter/releases)
[![Date](https://img.shields.io/badge/date-2023.08.13-c44d58.svg)](https://git.dotclear.watch/JcDenis/topWriter/releases)
[![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/topWriter)
[![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/topWriter/src/branch/master/LICENSE)
[![License](https://img.shields.io/github/license/JcDenis/topWriter)](https://git.dotclear.watch/JcDenis/topWriter/blob/master/LICENSE)
## ABOUT
## WHAT IS TOPWRITER ?
_topWriter_ is a plugin for the open-source web publishing software called [Dotclear](https://www.dotclear.org).
_Top writer_ is a plugin for the open-source
web publishing software called Dotclear.
> Show most active contributor on a widget.
Show most active contributor on a widget.
## REQUIREMENTS
* Dotclear 2.28
* PHP 8.1
* Dotclear permissions to manage widgets
_topWriter_ requires:
* permissions to manage widgets
* Dotclear 2.27
* PHP 7.4
## USAGE
@ -29,11 +32,10 @@ Or add contents to the backend dashboard from your preferences.
## LINKS
* [License](https://git.dotclear.watch/JcDenis/topWriter/src/branch/master/LICENSE)
* [Packages & details](https://git.dotclear.watch/JcDenis/topWriter/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/topWriter))
* [Sources & contributions](https://git.dotclear.watch/JcDenis/topWriter) (or on [GitHub](https://github.com/JcDenis/topWriter))
* [Issues & security](https://git.dotclear.watch/JcDenis/topWriter/issues) (or on [GitHub](https://github.com/JcDenis/topWriter/issues))
* [Discuss & help](http://forum.dotclear.org/viewtopic.php?pid=333002#p333002)
* License : [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html)
* Source & contribution : [Gitea Page](https://git.dotclear.watch/JcDenis/topWriter) or [GitHub Page](https://github.com/JcDenis/topWriter)
* Packages & details: [Gitea Page](https://git.dotclear.watch/JcDenis/topWriter/releases) or [Dotaddict Page](https://plugins.dotaddict.org/dc2/details/topWriter)
* Discuss and help : [Dotclear Forum](http://forum.dotclear.org/viewtopic.php?pid=333002#p333002)
## CONTRIBUTORS

View File

@ -1,26 +1,29 @@
<?php
/**
* @file
* @brief The plugin topWriter definition
* @ingroup topWriter
* @brief topWriter, a plugin for Dotclear 2
*
* @defgroup topWriter Plugin topWriter.
* @package Dotclear
* @subpackage Plugin
*
* Ranking of the most prolific writers and/or commentators.
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @author Jean-Christian Denis
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
if (!defined('DC_RC_PATH')) {
return null;
}
$this->registerModule(
'Top writer',
'Ranking of the most prolific writers and/or commentators',
'Jean-Christian Denis, Pierre Van Glabeke',
'1.4',
'1.3',
[
'requires' => [['core', '2.28']],
'permissions' => 'My',
'requires' => [['core', '2.27']],
'permissions' => dcCore::app()->auth->makePermissions([
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
]),
'type' => 'plugin',
'support' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/issues',
'details' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/src/branch/master/README.md',

View File

@ -2,11 +2,11 @@
<modules xmlns:da="http://dotaddict.org/da/">
<module id="topWriter">
<name>Top writer</name>
<version>1.4</version>
<version>1.3</version>
<author>Jean-Christian Denis, Pierre Van Glabeke</author>
<desc>Ranking of the most prolific writers and/or commentators</desc>
<file>https://git.dotclear.watch/JcDenis/topWriter/releases/download/v1.4/plugin-topWriter.zip</file>
<da:dcmin>2.28</da:dcmin>
<file>https://git.dotclear.watch/JcDenis/topWriter/releases/download/v1.3/plugin-topWriter.zip</file>
<da:dcmin>2.27</da:dcmin>
<da:details>https://git.dotclear.watch/JcDenis/topWriter/src/branch/master/README.md</da:details>
<da:support>https://git.dotclear.watch/JcDenis/topWriter/issues</da:support>
</module>

View File

@ -1,19 +1,22 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use Dotclear\App;
use dcCore;
use Dotclear\Core\Process;
/**
* @brief topWriter backend class.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Backend extends Process
{
public static function init(): bool
@ -27,11 +30,11 @@ class Backend extends Process
return false;
}
App::behavior()->addBehaviors([
'adminDashboardItemsV2' => BackendBehaviors::adminDashboardItemsV2(...),
'adminDashboardOptionsFormV2' => BackendBehaviors::adminDashboardOptionsFormV2(...),
'adminAfterDashboardOptionsUpdate' => BackendBehaviors::adminAfterDashboardOptionsUpdate(...),
'initWidgets' => Widgets::initWidgets(...),
dcCore::app()->addBehaviors([
'adminDashboardItemsV2' => [BackendBehaviors::class, 'adminDashboardItemsV2'],
'adminDashboardOptionsFormV2' => [BackendBehaviors::class, 'adminDashboardOptionsFormV2'],
'adminAfterDashboardOptionsUpdate' => [BackendBehaviors::class, 'adminAfterDashboardOptionsUpdate'],
'initWidgets' => [Widgets::class, 'initWidgets'],
]);
return true;

View File

@ -1,11 +1,21 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use ArrayObject;
use Dotclear\App;
use dcCore;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
@ -18,11 +28,9 @@ use Dotclear\Helper\Html\Form\{
use Dotclear\Helper\Html\Html;
/**
* @brief topWriter backend behaviors class.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
* @ingroup DC_PLUGIN_TOPWRITER
* @brief Display most active users - admin methods.
* @since 2.6
*/
class BackendBehaviors
{
@ -106,33 +114,33 @@ class BackendBehaviors
public static function adminAfterDashboardOptionsUpdate(?string $user_id): void
{
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsItems',
!empty($_POST['topWriterPostsItems']),
'boolean'
);
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsPeriod',
(string) $_POST['topWriterPostsPeriod'],
'string'
);
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsLimit',
(int) $_POST['topWriterPostsLimit'],
'integer'
);
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsItems',
!empty($_POST['topWriterCommentsItems']),
'boolean'
);
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsPeriod',
(string) $_POST['topWriterCommentsPeriod'],
'string'
);
App::auth()->prefs()->get('dashboard')->put(
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsLimit',
(int) $_POST['topWriterCommentsLimit'],
'integer'
@ -141,43 +149,43 @@ class BackendBehaviors
private static function setDefaultPref(): array
{
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterPostsItems')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterPostsItems')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsItems',
false,
'boolean'
);
}
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterPostsPeriod')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterPostsPeriod')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsPeriod',
'month',
'string'
);
}
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterPostsLimit')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterPostsLimit')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterPostsLimit',
10,
'integer'
);
}
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterCommentsItems')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterCommentsItems')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsItems',
false,
'boolean'
);
}
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterCommentsPeriod')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterCommentsPeriod')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsPeriod',
'month',
'string'
);
}
if (!App::auth()->prefs()->get('dashboard')->prefExists('topWriterCommentsLimit')) {
App::auth()->prefs()->get('dashboard')->put(
if (!dcCore::app()->auth->user_prefs->get('dashboard')->prefExists('topWriterCommentsLimit')) {
dcCore::app()->auth->user_prefs->get('dashboard')->put(
'topWriterCommentsLimit',
10,
'integer'
@ -185,12 +193,12 @@ class BackendBehaviors
}
return [
'topWriterPostsItems' => App::auth()->prefs()->get('dashboard')->get('topWriterPostsItems'),
'topWriterPostsPeriod' => App::auth()->prefs()->get('dashboard')->get('topWriterPostsPeriod'),
'topWriterPostsLimit' => App::auth()->prefs()->get('dashboard')->get('topWriterPostsLimit') ?? 10,
'topWriterCommentsItems' => App::auth()->prefs()->get('dashboard')->get('topWriterCommentsItems'),
'topWriterCommentsPeriod' => App::auth()->prefs()->get('dashboard')->get('topWriterCommentsPeriod'),
'topWriterCommentsLimit' => App::auth()->prefs()->get('dashboard')->get('topWriterCommentsLimit') ?? 10,
'topWriterPostsItems' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterPostsItems'),
'topWriterPostsPeriod' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterPostsPeriod'),
'topWriterPostsLimit' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterPostsLimit') ?? 10,
'topWriterCommentsItems' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterCommentsItems'),
'topWriterCommentsPeriod' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterCommentsPeriod'),
'topWriterCommentsLimit' => dcCore::app()->auth->user_prefs->get('dashboard')->get('topWriterCommentsLimit') ?? 10,
];
}
}

View File

@ -1,19 +1,22 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use Dotclear\App;
use dcCore;
use Dotclear\Core\Process;
/**
* @brief topWriter frontend class.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Frontend extends Process
{
public static function init(): bool
@ -27,7 +30,9 @@ class Frontend extends Process
return false;
}
App::behavior()->addBehavior('initWidgets', Widgets::initWidgets(...));
dcCore::app()->addBehaviors([
'initWidgets' => [Widgets::class, 'initWidgets'],
]);
return true;
}

View File

@ -1,19 +1,21 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use Dotclear\Module\MyPlugin;
/**
* @brief topWriter My helper.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class My extends MyPlugin
{
// Use default persmissions
}

View File

@ -1,34 +1,41 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use Dotclear\App;
use dcAuth;
use dcBlog;
use dcCore;
use dcUtils;
use Dotclear\Database\Statement\{
JoinStatement,
SelectStatement
};
use Dotclear\Helper\Date;
/**
* @brief topWriter utils class.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Utils
{
public static function posts(string $period, int $limit, bool $sort_desc = true): array
{
if (!App::blog()->isDefined()) {
// nullsafe
if (is_null(dcCore::app()->blog)) {
return [];
}
$sql = new SelectStatement();
$sql
->from($sql->as(App::con()->prefix() . App::blog()::POST_TABLE_NAME, 'P'))
->from($sql->as(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME, 'P'))
->columns([
$sql->count('*', 'count'),
'U.user_id',
@ -36,12 +43,12 @@ class Utils
->join(
(new JoinStatement())
->inner()
->from($sql->as(App::con()->prefix() . App::auth()::USER_TABLE_NAME, 'U'))
->from($sql->as(dcCore::app()->prefix . dcAuth::USER_TABLE_NAME, 'U'))
->on('U.user_id = P.user_id')
->statement()
)
->where('blog_id = ' . $sql->quote(App::blog()->id()))
->and('post_status = ' . App::blog()::POST_PUBLISHED)
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->and('post_status = ' . dcBlog::POST_PUBLISHED)
->and('user_status = 1')
->group('U.user_id')
->order('count ' . ($sort_desc ? 'DESC' : 'ASC') . ' , U.user_id ASC')
@ -60,7 +67,7 @@ class Utils
while ($rs->fetch()) {
$sql = new SelectStatement();
$user = $sql
->from(App::con()->prefix() . App::auth()::USER_TABLE_NAME)
->from(dcCore::app()->prefix . dcAuth::USER_TABLE_NAME)
->column('*')
->where('user_id = ' . $sql->quote($rs->f('user_id')))
->select();
@ -69,7 +76,7 @@ class Utils
continue;
}
$author = App::users()->getUserCN(
$author = dcUtils::getUserCN(
$user->f('user_id'),
$user->f('user_name'),
$user->f('user_firstname'),
@ -80,9 +87,9 @@ class Utils
}
$i++;
if (App::blog()->settings()->get('authormode')->get('authormode_active')) {
if (dcCore::app()->blog->settings->get('authormode')->get('authormode_active')) {
$res[$i]['author_link'] = '<a href="' .
App::blog()->url() . App::url()->getBase('author') . '/' . $user->f('user_id') . '" ' .
dcCore::app()->blog->url . dcCore::app()->url->getBase('author') . '/' . $user->f('user_id') . '" ' .
'title="' . __('Author posts') . '">' . $author . '</a>';
} elseif ($user->f('user_url')) {
$res[$i]['author_link'] = '<a href="' . $user->f('user_url') . '" title="' .
@ -102,22 +109,23 @@ class Utils
public static function comments(string $period, int $limit, bool $sort_desc = true, bool $exclude = false): array
{
if (!App::blog()->isDefined()) {
// nullsafe
if (is_null(dcCore::app()->blog)) {
return [];
}
$sql = new SelectStatement();
$sql
->from($sql->as(App::con()->prefix() . App::blog()::POST_TABLE_NAME, 'P'))
->from($sql->as(App::con()->prefix() . App::blog()::COMMENT_TABLE_NAME, 'C'))
->from($sql->as(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME, 'P'))
->from($sql->as(dcCore::app()->prefix . dcBlog::COMMENT_TABLE_NAME, 'C'))
->columns([
$sql->count('*', 'count'),
'comment_email',
])
->where('blog_id = ' . $sql->quote(App::blog()->id()))
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->and('P.post_id = C.post_id')
->and('post_status = ' . App::blog()::POST_PUBLISHED)
->and('comment_status = ' . App::blog()::COMMENT_PUBLISHED)
->and('post_status = ' . dcBlog::POST_PUBLISHED)
->and('comment_status = ' . dcBlog::COMMENT_PUBLISHED)
->group('comment_email')
->order('count ' . ($sort_desc ? 'DESC' : 'ASC'))
->limit(abs((int) $limit))
@ -128,16 +136,16 @@ class Utils
if ($exclude) {
$sql->and('comment_email NOT IN (' .
(new SelectStatement())
->from($sql->as(App::con()->prefix() . App::auth()::USER_TABLE_NAME, 'U'))
->from($sql->as(dcCore::app()->prefix . dcAuth::USER_TABLE_NAME, 'U'))
->column('U.user_email')
->join(
(new JoinStatement())
->inner()
->from($sql->as(App::con()->prefix() . App::blog()::POST_TABLE_NAME, 'P'))
->from($sql->as(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME, 'P'))
->on('P.user_id = U.user_id')
->statement()
)
->where('blog_id = ' . $sql->quote(App::blog()->id()))
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->group('U.user_email')
->statement() .
')');
@ -153,7 +161,7 @@ class Utils
while ($rs->fetch()) {
$sql = new SelectStatement();
$user = $sql
->from(App::con()->prefix() . App::blog()::COMMENT_TABLE_NAME)
->from(dcCore::app()->prefix . dcBlog::COMMENT_TABLE_NAME)
->column('*')
->where('comment_email = ' . $sql->quote($rs->f('comment_email')))
->order('comment_dt DESC')

View File

@ -1,21 +1,24 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\topWriter;
use Dotclear\App;
use dcCore;
use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\widgets\WidgetsStack;
use Dotclear\Plugin\widgets\WidgetsElement;
/**
* @brief topWriter widgets class.
* @ingroup topWriter
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Widgets
{
public static function initWidgets(WidgetsStack $w): void
@ -25,7 +28,7 @@ class Widgets
->create(
'topcom',
__('Top writer: comments'),
self::topComWidget(...),
[self::class, 'topComWidget'],
null,
__('List users who write more comments')
)
@ -75,7 +78,7 @@ class Widgets
->create(
'toppost',
__('Top writer: entries'),
self::topPostWidget(...),
[self::class, 'topPostWidget'],
null,
__('List users who write more posts')
)
@ -117,7 +120,7 @@ class Widgets
public static function topComWidget(WidgetsElement $w): string
{
if ($w->offline || !$w->checkHomeOnly(App::url()->type)) {
if ($w->offline || !$w->checkHomeOnly(dcCore::app()->url->type)) {
return '';
}
@ -137,7 +140,7 @@ class Widgets
public static function topPostWidget(WidgetsElement $w): string
{
if ($w->offline || !$w->checkHomeOnly(App::url()->type)) {
if ($w->offline || !$w->checkHomeOnly(dcCore::app()->url->type)) {
return '';
}