code review (statement, nullsafe, static method)

This commit is contained in:
Jean-Christian Denis 2023-04-24 01:40:03 +02:00
parent 3f42099051
commit a365f601da
Signed by: JcDenis
GPG key ID: 1B5B8C5B90B6C951
4 changed files with 251 additions and 108 deletions

View file

@ -14,18 +14,15 @@ declare(strict_types=1);
namespace Dotclear\Plugin\whiteListCom; namespace Dotclear\Plugin\whiteListCom;
/* dotclear ns */
use dcCore; use dcCore;
use dcNamespace; use dcNamespace;
use dcNsProcess; use dcNsProcess;
/* php ns */
use Exception; use Exception;
class Install extends dcNsProcess class Install extends dcNsProcess
{ {
// Module specs // Module specs
private static $mod_conf = [ private static array $mod_conf = [
[ [
'unmoderated', 'unmoderated',
'[]', '[]',
@ -49,7 +46,11 @@ class Install extends dcNsProcess
public static function process(): bool public static function process(): bool
{ {
if (!sestaticlf::$init) { if (!static::$init) {
return false;
}
if (is_null(dcCore::app()->blog)) {
return false; return false;
} }
@ -89,15 +90,15 @@ class Install extends dcNsProcess
); );
while ($record->fetch()) { while ($record->fetch()) {
if (preg_match('/^whiteListCom(.*?)$/', $record->setting_id, $match)) { if (preg_match('/^whiteListCom(.*?)$/', $record->f('setting_id'), $match)) {
$value = @unserialize(@base64_decode($record->setting_value)); $value = @unserialize(@base64_decode($record->f('setting_value')));
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME); $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME);
$cur->setting_id = $match[1]; $cur->setField('setting_id', $match[1]);
$cur->setting_ns = My::id(); $cur->setField('setting_ns', My::id());
$cur->setting_value = is_array($value) ? json_encode($value) : '[]'; $cur->setField('setting_value', is_array($value) ? json_encode($value) : '[]');
$cur->update( $cur->update(
"WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'whiteListCom' " . "WHERE setting_id = '" . $record->f('setting_id') . "' and setting_ns = 'whiteListCom' " .
'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' ")) 'AND blog_id ' . (null === $record->f('blog_id') ? 'IS NULL ' : ("= '" . dcCore::app()->con->escapeStr((string) $record->f('blog_id')) . "' "))
); );
} }
} }

View file

@ -16,13 +16,13 @@ namespace Dotclear\Plugin\whiteListCom;
use dcCore; use dcCore;
use dcPage; use dcPage;
use dcSpamFilter;
use Dotclear\Helper\Html\Form\{ use Dotclear\Helper\Html\Form\{
Checkbox, Checkbox,
Hidden Hidden
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Helper\Network\Http; use Dotclear\Helper\Network\Http;
use Dotclear\Plugin\antispam\SpamFilter;
use Exception; use Exception;
/** /**
@ -30,17 +30,23 @@ use Exception;
* @brief Filter for reserved names. * @brief Filter for reserved names.
* @since 2.6 * @since 2.6
*/ */
class ReservedWhiteList extends dcSpamFilter class ReservedWhiteList extends SpamFilter
{ {
public $name = 'Reserved names'; public $name = 'Reserved names';
public $has_gui = true; public $has_gui = true;
/**
* @return void
*/
protected function setInfo() protected function setInfo()
{ {
$this->name = __('Reserved names'); $this->name = __('Reserved names');
$this->description = __('Whitelist of reserved names of users'); $this->description = __('Whitelist of reserved names of users');
} }
/**
* @return void|null|bool
*/
public function isSpam($type, $author, $email, $site, $ip, $content, $post_id, &$status) public function isSpam($type, $author, $email, $site, $ip, $content, $post_id, &$status)
{ {
if ($type != 'comment') { if ($type != 'comment') {
@ -50,9 +56,7 @@ class ReservedWhiteList extends dcSpamFilter
$throw = false; $throw = false;
try { try {
$wlc = new Utils(); if (true === Utils::isReserved($author, $email)) {
if (true === $wlc->isReserved($author, $email)) {
$status = 'reserved name'; $status = 'reserved name';
//return true; //return true;
$throw = true; $throw = true;
@ -68,6 +72,9 @@ class ReservedWhiteList extends dcSpamFilter
} }
} }
/**
* @return string
*/
public function getStatusMessage($status, $comment_id) public function getStatusMessage($status, $comment_id)
{ {
return __('This name is reserved to an other user.'); return __('This name is reserved to an other user.');
@ -75,40 +82,41 @@ class ReservedWhiteList extends dcSpamFilter
public function gui(string $url): string public function gui(string $url): string
{ {
$wlc = new Utils();
$comments = []; $comments = [];
try { try {
if (!empty($_POST['update_reserved'])) { if (!empty($_POST['update_reserved'])) {
$wlc->emptyReserved(); Utils::emptyReserved();
foreach ($_POST['reserved'] as $i => $name) { foreach ($_POST['reserved'] as $i => $name) {
$wlc->addReserved($name, $_POST['reserved_email'][$i]); Utils::addReserved($name, $_POST['reserved_email'][$i]);
} }
$wlc->commit(); Utils::commit();
dcPage::addSuccessNotice(__('Reserved names have been successfully updated.')); dcPage::addSuccessNotice(__('Reserved names have been successfully updated.'));
Http::redirect($url); Http::redirect($url);
} }
$comments = $wlc->getCommentsUsers(); $comments = Utils::getCommentsUsers();
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
$res = '<form action="' . Html::escapeURL($url) . '" method="post">' . $res = '<form action="' . Html::escapeURL($url) . '" method="post">' .
'<p>' . __('Check the users who can make comments without being moderated.') . '</p>' . '<p>' . __('Check the users who can make comments without being moderated.') . '</p>' .
'<p>' . __('Comments authors list') . '</p>' . '<div class="table-outer">' .
'<table class="clear">' . '<table class="clear">' .
'<caption>' . __('Comments authors list') . '</caption>' .
'<thead><tr><th>' . __('Author') . '</th><th>' . __('Email') . '</th></tr></thead>' . '<thead><tr><th>' . __('Author') . '</th><th>' . __('Email') . '</th></tr></thead>' .
'<tbody>'; '<tbody>';
$i = 0; $i = 0;
foreach ($comments as $user) { foreach ($comments as $user) {
$res .= '<tr class="line">' . $checked = null === Utils::isReserved($user['name'], $user['email']);
$res .= '<tr class="line' . ($checked ? '' : ' offline') . '">' .
'<td class="nowrap">' . '<td class="nowrap">' .
(new Checkbox(['reserved[' . $i . ']'], (null === $wlc->isReserved($user['name'], $user['email']))))->value($user['name'])->render() . (new Checkbox(['reserved[' . $i . ']'], $checked))->value($user['name'])->render() .
(new Hidden(['reserved_email[' . $i . ']'], $user['email']))->render() . (new Hidden(['reserved_email[' . $i . ']'], $user['email']))->render() .
' ' . $user['name'] . '</td>' . ' ' . $user['name'] . '</td>' .
'<td class="nowrap">' . $user['email'] . '</td>' . '<td class="nowrap maximal">' . $user['email'] . '</td>' .
'</tr>'; '</tr>';
$i++; $i++;
} }

View file

@ -16,10 +16,10 @@ namespace Dotclear\Plugin\whiteListCom;
use dcCore; use dcCore;
use dcPage; use dcPage;
use dcSpamFilter;
use Dotclear\Helper\Html\Form\Checkbox; use Dotclear\Helper\Html\Form\Checkbox;
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Helper\Network\Http; use Dotclear\Helper\Network\Http;
use Dotclear\Plugin\antispam\SpamFilter;
use Exception; use Exception;
/** /**
@ -29,17 +29,23 @@ use Exception;
* *
* This filter is used only if comments are moderates * This filter is used only if comments are moderates
*/ */
class UnmoderatedWhiteList extends dcSpamFilter class UnmoderatedWhiteList extends SpamFilter
{ {
public $name = 'Unmoderated authors'; public $name = 'Unmoderated authors';
public $has_gui = true; public $has_gui = true;
/**
* @return void
*/
protected function setInfo() protected function setInfo()
{ {
$this->name = __('Unmoderated authors'); $this->name = __('Unmoderated authors');
$this->description = __('Whitelist of unmoderated authors'); $this->description = __('Whitelist of unmoderated authors');
} }
/**
* @return void|null|bool
*/
public function isSpam($type, $author, $email, $site, $ip, $content, $post_id, &$status) public function isSpam($type, $author, $email, $site, $ip, $content, $post_id, &$status)
{ {
if ($type != 'comment' if ($type != 'comment'
@ -49,8 +55,7 @@ class UnmoderatedWhiteList extends dcSpamFilter
} }
try { try {
$wlc = new Utils(); if (Utils::isUnmoderated($email)) {
if ($wlc->isUnmoderated($email)) {
$status = 'unmoderated'; $status = 'unmoderated';
# return true in order to change comment_status after # return true in order to change comment_status after
@ -69,23 +74,23 @@ class UnmoderatedWhiteList extends dcSpamFilter
try { try {
if (!empty($_POST['update_unmoderated'])) { if (!empty($_POST['update_unmoderated'])) {
$wlc->emptyUnmoderated(); Utils::emptyUnmoderated();
foreach ($_POST['unmoderated'] as $email) { foreach ($_POST['unmoderated'] as $email) {
$wlc->addUnmoderated($email); Utils::addUnmoderated($email);
} }
$wlc->commit(); Utils::commit();
dcPage::addSuccessNotice(__('Unmoderated names have been successfully updated.')); dcPage::addSuccessNotice(__('Unmoderated names have been successfully updated.'));
Http::redirect($url); Http::redirect($url);
} }
$posts = $wlc->getPostsUsers(); $posts = Utils::getPostsUsers();
$comments = $wlc->getCommentsUsers(); $comments = Utils::getCommentsUsers();
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
$res = ''; $res = '';
if (dcCore::app()->blog->settings->get('system')->get('comments_pub')) { if (!is_null(dcCore::app()->blog) && dcCore::app()->blog->settings->get('system')->get('comments_pub')) {
$res .= '<p class="message">' . $res .= '<p class="message">' .
__('This filter is used only if comments are moderates') . __('This filter is used only if comments are moderates') .
'</p>'; '</p>';
@ -93,42 +98,46 @@ class UnmoderatedWhiteList extends dcSpamFilter
$res .= '<form action="' . Html::escapeURL($url) . '" method="post">' . $res .= '<form action="' . Html::escapeURL($url) . '" method="post">' .
'<p>' . __('Check the users who can make comments without being moderated.') . '</p>' . '<p>' . __('Check the users who can make comments without being moderated.') . '</p>' .
'<div class="two-cols">' . '<div class="two-boxes">' .
'<div class="col">' . '<div class="box odd">' .
'<p>' . __('Posts authors list') . '</p>' . '<div class="table-outer">' .
'<table class="clear">' . '<table class="clear">' .
'<caption>' . __('Posts authors list') . '</caption>' .
'<thead><tr><th>' . __('Name') . '</th><th>' . __('Email') . '</th></tr></thead>' . '<thead><tr><th>' . __('Name') . '</th><th>' . __('Email') . '</th></tr></thead>' .
'<tbody>'; '<tbody>';
foreach ($posts as $user) { foreach ($posts as $user) {
$res .= '<tr class="line">' . $checked = Utils::isUnmoderated($user['email']);
$res .= '<tr class="line' . ($checked ? '' : ' offline') . '">' .
'<td class="nowrap">' . '<td class="nowrap">' .
(new Checkbox(['unmoderated[]'], $wlc->isUnmoderated($user['email'])))->value($user['email'])->render() . (new Checkbox(['unmoderated[]'], $checked))->value($user['email'])->render() .
' ' . $user['name'] . '</td>' . ' ' . $user['name'] . '</td>' .
'<td class="nowrap">' . $user['email'] . '</td>' . '<td class="nowrap">' . $user['email'] . '</td>' .
'</tr>'; '</tr>';
} }
$res .= '</tbody>' . $res .= '</tbody>' .
'</table>' . '</table></div>' .
'</div>' . '</div>' .
'<div class="col">' . '<div class="box even">' .
'<p>' . __('Comments authors list') . '</p>' . '<div class="table-outer">' .
'<table class="clear">' . '<table class="clear">' .
'<caption>' . __('Comments authors list') . '</caption>' .
'<thead><tr><th>' . __('Author') . '</th><th>' . __('Email') . '</th></tr></thead>' . '<thead><tr><th>' . __('Author') . '</th><th>' . __('Email') . '</th></tr></thead>' .
'<tbody>'; '<tbody>';
foreach ($comments as $user) { foreach ($comments as $user) {
$res .= '<tr class="line">' . $checked = Utils::isUnmoderated($user['email']);
$res .= '<tr class="line' . ($checked ? '' : ' offline') . '">' .
'<td class="nowrap">' . '<td class="nowrap">' .
(new Checkbox(['unmoderated[]'], $wlc->isUnmoderated($user['email'])))->value($user['email'])->render() . (new Checkbox(['unmoderated[]'], $checked))->value($user['email'])->render() .
' ' . $user['name'] . '</td>' . ' ' . $user['name'] . '</td>' .
'<td class="nowrap">' . $user['email'] . '</td>' . '<td class="nowrap">' . $user['email'] . '</td>' .
'</tr>'; '</tr>';
} }
$res .= '</tbody>' . $res .= '</tbody>' .
'</table>' . '</table></div>' .
'</div>' . '</div>' .
'</div>' . '</div>' .
'<p><input type="submit" id="update_unmoderated" name="update_unmoderated" value="' . __('Save') . '" />' . '<p><input type="submit" id="update_unmoderated" name="update_unmoderated" value="' . __('Save') . '" />' .

View file

@ -14,10 +14,13 @@ declare(strict_types=1);
namespace Dotclear\Plugin\whiteListCom; namespace Dotclear\Plugin\whiteListCom;
/* dotclear ns */
use dcBlog; use dcBlog;
use dcCore; use dcCore;
use dcUtils; use dcUtils;
use Dotclear\Database\Statement\{
JoinStatement,
SelectStatement,
};
/** /**
* @ingroup DC_PLUGIN_WHITELISTCOM * @ingroup DC_PLUGIN_WHITELISTCOM
@ -26,36 +29,61 @@ use dcUtils;
*/ */
class Utils class Utils
{ {
public $con; /** @var bool $init preload check */
public $blog; private static bool $init = false;
public $settings;
private $unmoderated = []; /** @var array $unmoderated List of unmoderated users */
private $reserved = []; private static array $unmoderated = [];
public function __construct() /** @var array $unmoderated List of reserved name */
private static array $reserved = [];
/**
* Initialize properties.
*/
private static function init(): void
{ {
$this->con = dcCore::app()->con; if (self::$init) {
$this->blog = dcCore::app()->con->escapeStr((string) dcCore::app()->blog->id); return;
$this->settings = dcCore::app()->blog->settings->get(My::id());
$this->unmoderated = self::decode($this->settings->get('unmoderated'));
$this->reserved = self::decode($this->settings->get('reserved'));
} }
public function commit(): void if (is_null(dcCore::app()->blog)) {
return;
}
$s = dcCore::app()->blog->settings->get(My::id());
self::$unmoderated = self::decode($s->get('unmoderated'));
self::$reserved = self::decode($s->get('reserved'));
self::$init = true;
}
/**
* Save changes.
*/
public static function commit(): void
{ {
$this->settings->put( if (is_null(dcCore::app()->blog)) {
return;
}
self::init();
$s = dcCore::app()->blog->settings->get(My::id());
$s->put(
'unmoderated', 'unmoderated',
self::encode($this->unmoderated), self::encode(self::$unmoderated),
'string', 'string',
'Whitelist of unmoderated users on comments', 'Whitelist of unmoderated users on comments',
true, true,
false false
); );
$this->settings->put( $s->put(
'reserved', 'reserved',
self::encode($this->reserved), self::encode(self::$reserved),
'string', 'string',
'Whitelist of reserved names on comments', 'Whitelist of reserved names on comments',
true, true,
@ -63,64 +91,122 @@ class Utils
); );
} }
# Return /**
# true if it is a reserved name with wrong email * Check if a name is reserved.
# false if it is not a reserved name *
# null if it is a reserved name with right email * Return:
public function isReserved($author, $email): ?bool * - true if it is a reserved name with wrong email
* - false if it is not a reserved name
* - null if it is a reserved name with right email
*
* @param string $author The author
* @param string $email The email
*
* @return null|bool The reserved state
*/
public static function isReserved(string $author, string $email): ?bool
{ {
if (!isset($this->reserved[$author])) { self::init();
if (!isset(self::$reserved[$author])) {
return false; return false;
} elseif ($this->reserved[$author] != $email) { } elseif (self::$reserved[$author] != $email) {
return true; return true;
} }
return null; return null;
} }
# You must do a commit to save this change /**
public function addReserved($author, $email): bool * Add a reserved user.
*
* You must do a Utils::commit() to save this change
*
* @param string $author The author
* @param string $email The email
*/
public static function addReserved(string $author, string $email): void
{ {
$this->reserved[$author] = $email; self::init();
return true; self::$reserved[$author] = $email;
} }
# You must do a commit to save this change /**
public function emptyReserved(): void * Clean reserved names list.
*
* You must do a Utils::commit() to save this change
*/
public static function emptyReserved(): void
{ {
$this->reserved = []; self::init();
self::$reserved = [];
} }
# Return /**
# true if it is known as an unmoderated email else false * Check if an email is unmoderated.
public function isUnmoderated($email): bool *
* Return:
* - true if it is known as an unmoderated email
* - false else
*
* @param string $email The email
*
* @return bool The reserved state
*/
public static function isUnmoderated(string $email): bool
{ {
return in_array($email, $this->unmoderated); self::init();
return in_array($email, self::$unmoderated);
} }
# You must do a commit to save this change /**
public function addUnmoderated($email): ?bool * Add a unmoderated user.
*
* You must do a Utils::commit() to save this change
*
* @param string $email The email
*/
public static function addUnmoderated(string $email): void
{ {
if (!in_array($email, $this->unmoderated)) { self::init();
$this->unmoderated[] = $email;
return true; if (!in_array($email, self::$unmoderated)) {
self::$unmoderated[] = $email;
}
} }
return null; /**
* Clean unmoderated users list.
*
* You must do a Utils::commit() to save this change
*/
public static function emptyUnmoderated(): void
{
self::init();
self::$unmoderated = [];
} }
# You must do a commit to save this change /**
public function emptyUnmoderated(): void * Get posts users.
*
* @return array The users name/email pairs
*/
public static function getPostsUsers(): array
{ {
$this->unmoderated = []; if (is_null(dcCore::app()->blog)) {
return [];
} }
public function getPostsUsers(): array
{
$users = [];
$rs = dcCore::app()->blog->getPostsUsers(); $rs = dcCore::app()->blog->getPostsUsers();
if ($rs->isEmpty()) {
return [];
}
$users = [];
while ($rs->fetch()) { while ($rs->fetch()) {
$name = dcUtils::getUserCN( $name = dcUtils::getUserCN(
$rs->f('user_id'), $rs->f('user_id'),
@ -137,16 +223,41 @@ class Utils
return $users; return $users;
} }
public function getCommentsUsers(): array /**
* Get comments users.
*
* @return array The users name/email pairs
*/
public static function getCommentsUsers(): array
{ {
if (is_null(dcCore::app()->blog)) {
return [];
}
$sql = new SelectStatement();
$rs = $sql->from($sql->as(dcCore::app()->prefix . dcBlog::COMMENT_TABLE_NAME, 'C'))
->columns([
'comment_author',
'comment_email',
])
->join(
(new JoinStatement())
->left()
->from($sql->as(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME, 'P'))
->on('C.post_id = P.post_id')
->statement()
)
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->and('comment_trackback = 0')
->and("comment_email != ''")
->group('comment_email, comment_author') // Added author to fix postgreSql
->select();
if (is_null($rs) || $rs->isEmpty()) {
return [];
}
$users = []; $users = [];
$rs = $this->con->select(
'SELECT comment_author, comment_email ' .
'FROM ' . dcCore::app()->prefix . dcBlog::COMMENT_TABLE_NAME . ' C ' .
'LEFT JOIN ' . dcCore::app()->prefix . 'post P ON C.post_id=P.post_id ' .
"WHERE blog_id='" . $this->blog . "' AND comment_trackback=0 " .
'GROUP BY comment_email, comment_author ' // Added author to fix postgreSql
);
while ($rs->fetch()) { while ($rs->fetch()) {
$users[] = [ $users[] = [
'name' => $rs->f('comment_author'), 'name' => $rs->f('comment_author'),
@ -157,13 +268,27 @@ class Utils
return $users; return $users;
} }
/**
* Encode settings.
*
* @param array|string $x The value to encode
*
* @return string The encoded value
*/
public static function encode($x): string public static function encode($x): string
{ {
$y = is_array($x) ? $x : []; $y = is_array($x) ? $x : [];
return json_encode($y); return (string) json_encode($y);
} }
/**
* Decode settings.
*
* @param string $x The value to decode
*
* @return array The decoded value
*/
public static function decode($x): array public static function decode($x): array
{ {
$y = json_decode($x, true); $y = json_decode($x, true);