From acce51b890ebeeb0e9b55a43e5468accb0ecff35 Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Sat, 6 Nov 2021 21:15:51 +0100 Subject: [PATCH] add top writer to dashboard --- CHANGELOG.md | 6 +- _admin.php | 194 +++++++++++++++++++++++++++++++- _define.php | 9 +- _prepend.php | 17 +++ _public.php | 9 +- _widgets.php | 242 +++++++--------------------------------- inc/class.topwriter.php | 189 +++++++++++++++++++++++++++++++ locales/fr/main.po | 70 ++++++------ 8 files changed, 486 insertions(+), 250 deletions(-) create mode 100644 _prepend.php create mode 100644 inc/class.topwriter.php diff --git a/CHANGELOG.md b/CHANGELOG.md index dcfe970..77c9e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ -0.8.2 - dev +dev - [ ] literal rank of writer depending of num of com -- [ ] add dashboard module +- add dashboard module +- update translations +- update to PSR12 0.8.1 - 2021.09.17 - fix plurals and better translation diff --git a/_admin.php b/_admin.php index 459867f..5a9ccda 100644 --- a/_admin.php +++ b/_admin.php @@ -1,18 +1,202 @@ addBehavior( + 'adminDashboardItems', + ['topWriterAdmin', 'adminDashboardItems'] +); +$core->addBehavior( + 'adminDashboardOptionsForm', + ['topWriterAdmin', 'adminDashboardOptionsForm'] +); +$core->addBehavior( + 'adminAfterDashboardOptionsUpdate', + ['topWriterAdmin', 'adminAfterDashboardOptionsUpdate'] +); + +/** + * @ingroup DC_PLUGIN_TOPWRITER + * @brief Display most active users - admin methods. + * @since 2.6 + */ +class topWriterAdmin +{ + public static function adminDashboardItems(dcCore $core, $__dashboard_items) + { + $pref = self::setDefaultPref($core); + + # top posts + if ($pref['topWriterPostsItems']) { + $lines = topWriter::posts($core, $pref['topWriterPostsPeriod'], $pref['topWriterPostsLimit']); + if (empty($lines)) { + return null; + } + + $li = []; + foreach ($lines as $k => $line) { + $li[] = sprintf('
  • %s %s (%s)
  • ', $k, $line['author'], $line['count']); + } + + # Display + $__dashboard_items[0][] = '
    ' . + '

    ' . html::escapeHTML(__('Top writer: entries')) . '

    ' . + '' . + '
    '; + } + + # top comments + if ($pref['topWriterCommentsItems']) { + $lines = topWriter::comments($core, $pref['topWriterCommentsPeriod'], $pref['topWriterCommentsLimit']); + if (empty($lines)) { + return null; + } + + $li = []; + foreach ($lines as $k => $line) { + $li[] = sprintf('
  • %s %s (%s)
  • ', $k, $line['author'], $line['count']); + } + + # Display + $__dashboard_items[0][] = '
    ' . + '

    ' . html::escapeHTML(__('Top writer: comments')) . '

    ' . + '' . + '
    '; + } + } + + public static function adminDashboardOptionsForm(dcCore $core) + { + $pref = self::setDefaultPref($core); + + echo + '
    ' . + '

    ' . __('Top writer: entries') . '

    ' . + '

    ' . + '

    ' . + form::combo('topWriterPostsPeriod', topWriter::periods(), $pref['topWriterPostsPeriod']) . '

    ' . + '

    ' . + form::number('topWriterPostsLimit', ['min' => 1, 'max' => 20, 'default' => $pref['topWriterPostsLimit']]) . '

    ' . + '
    ' . + + '
    ' . + '

    ' . __('Top writer: comments') . '

    ' . + '

    ' . + '

    ' . + form::combo('topWriterCommentsPeriod', topWriter::periods(), $pref['topWriterCommentsPeriod']) . '

    ' . + '

    ' . + form::number('topWriterCommentsLimit', ['min' => 1, 'max' => 20, 'default' => $pref['topWriterCommentsLimit']]) . '

    ' . + '
    '; + } + + public static function adminAfterDashboardOptionsUpdate($user_id) + { + global $core; + + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsItems', + !empty($_POST['topWriterPostsItems']), + 'boolean' + ); + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsPeriod', + (string) $_POST['topWriterPostsPeriod'], + 'string' + ); + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsLimit', + (int) $_POST['topWriterPostsLimit'], + 'integer' + ); + + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsItems', + !empty($_POST['topWriterCommentsItems']), + 'boolean' + ); + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsPeriod', + (string) $_POST['topWriterCommentsPeriod'], + 'string' + ); + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsLimit', + (int) $_POST['topWriterCommentsLimit'], + 'integer' + ); + } + + private static function setDefaultPref($core) + { + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsItems')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsItems', + false, + 'boolean' + ); + } + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsPeriod')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsPeriod', + 'month', + 'string' + ); + } + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsLimit')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterPostsLimit', + 10, + 'integer' + ); + } + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsItems')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsItems', + false, + 'boolean' + ); + } + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsPeriod')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsPeriod', + 'month', + 'string' + ); + } + if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsLimit')) { + $core->auth->user_prefs->dashboard->put( + 'topWriterCommentsLimit', + 10, + 'integer' + ); + } + + return [ + 'topWriterPostsItems' => $core->auth->user_prefs->dashboard->get('topWriterPostsItems'), + 'topWriterPostsPeriod' => $core->auth->user_prefs->dashboard->get('topWriterPostsPeriod'), + 'topWriterPostsLimit' => $core->auth->user_prefs->dashboard->get('topWriterPostsLimit') ?? 10, + 'topWriterCommentsItems' => $core->auth->user_prefs->dashboard->get('topWriterCommentsItems'), + 'topWriterCommentsPeriod' => $core->auth->user_prefs->dashboard->get('topWriterCommentsPeriod'), + 'topWriterCommentsLimit' => $core->auth->user_prefs->dashboard->get('topWriterCommentsLimit') ?? 10 + ]; + } +} diff --git a/_define.php b/_define.php index 655a843..a61645d 100644 --- a/_define.php +++ b/_define.php @@ -1,16 +1,15 @@ registerModule( 'details' => 'http://plugins.dotaddict.org/dc2/details/topWriter', 'repository' => 'https://raw.githubusercontent.com/JcDenis/topWriter/master/dcstore.xml' ] -); \ No newline at end of file +); diff --git a/_prepend.php b/_prepend.php new file mode 100644 index 0000000..384aa68 --- /dev/null +++ b/_prepend.php @@ -0,0 +1,17 @@ +create( 'topcom', @@ -33,7 +32,7 @@ class topWriterWidget ->addTitle(__('Top comments')) ->setting( 'text', - __('Text:'), + __('Text:') . ' (%rank%, %author%, %count%)', '%author% (%count%)', 'text' ) @@ -42,13 +41,7 @@ class topWriterWidget __('Period:'), 'year', 'combo', - [ - __('day') => 'day', - __('week') => 'week', - __('month') => 'month', - __('year') => 'year', - __('from begining') => '' - ] + topWriter::periods() ) ->setting( 'sort', @@ -56,8 +49,8 @@ class topWriterWidget 'desc', 'combo', [ - __('Ascending') => 'asc', - __('Descending') => 'desc' + __('Ascending') => 'asc', + __('Descending') => 'desc' ] ) ->setting( @@ -89,7 +82,7 @@ class topWriterWidget ->addTitle(__('Top entries')) ->setting( 'text', - __('Text:'), + __('Text:') . ' (%rank%, %author%, %count%)', '%author% (%count%)', 'text' ) @@ -98,21 +91,16 @@ class topWriterWidget __('Period:'), 'year', 'combo', - [ - __('day') => 'day', - __('week') => 'week', - __('month') => 'month', - __('year') => 'year', - __('from begining') => '' - ] + topWriter::periods() ) ->setting( 'sort', - __('Sort:'),'desc', + __('Sort:'), + 'desc', 'combo', [ - __('Ascending') => 'asc', - __('Descending') => 'desc' + __('Ascending') => 'asc', + __('Descending') => 'desc' ] ) ->setting( @@ -131,85 +119,15 @@ class topWriterWidget { global $core; - if ($w->offline) { + if ($w->offline + || ($w->homeonly == 1 && !$core->url->isHome($core->url->type)) + || ($w->homeonly == 2 && $core->url->isHome($core->url->type)) + ) { return null; } - if (($w->homeonly == 1 && !$core->url->isHome($core->url->type)) - || ($w->homeonly == 2 && $core->url->isHome($core->url->type))) { - return null; - } - - $req = - 'SELECT COUNT(*) AS count, comment_email ' . - "FROM " . $core->prefix . "post P, " . $core->prefix . "comment C " . - 'WHERE P.post_id=C.post_id ' . - "AND blog_id='" . $core->con->escape($core->blog->id) . "' " . - 'AND post_status=1 AND comment_status=1 ' . - self::period('comment_dt', $w->period); - - if ($w->exclude) { - $req .= - 'AND comment_email NOT IN (' . - ' SELECT U.user_email ' . - ' FROM ' . $core->prefix . 'user U' . - ' INNER JOIN ' . $core->prefix . 'post P ON P.user_id = U.user_id ' . - " WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " . - ' GROUP BY U.user_email) '; - } - - $req .= - 'GROUP BY comment_email ' . - 'ORDER BY count ' . ($w->sort == 'asc' ? 'ASC' : 'DESC') . ' ' . - $core->con->limit(abs((integer) $w->limit)); - - $rs = $core->con->select($req); - - if ($rs->isEmpty()) { - return null; - } - - $content = ''; - $i = 0; - while($rs->fetch()) { - $user = $core->con->select( - "SELECT * FROM " . $core->prefix . "comment " . - "WHERE comment_email='" . $rs->comment_email . "' " . - 'ORDER BY comment_dt DESC' - ); - - if (!$user->comment_author) { - continue; - } - - $i++; - $rank = '' . $i . ''; - - if ($user->comment_site) { - $author = '' . $user->comment_author . ''; - } else { - $author = $user->comment_author; - } - $author = '' . $author . ''; - - if ($rs->count == 0) { - $count = __('no comments'); - } else { - $count = sprintf(__('one comment', '%s comments', $rs->count), $rs->count); - } - - $content .= sprintf( - '
  • %s
  • ', - str_replace( - ['%rank%', '%author%', '%count%'], - [$rank, $author, $count], - $w->text - ) - ); - } - - if ($i < 1) { + $lines = topWriter::comments($core, $w->period, $w->limit, $w->sort == 'desc', $w->exclude); + if (empty($lines)) { return null; } @@ -218,7 +136,7 @@ class topWriterWidget 'topcomments ' . $w->class, '', ($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') . - sprintf('', $content) + sprintf('', implode('', self::lines($lines, 'comments', $w->text))) ); } @@ -226,80 +144,15 @@ class topWriterWidget { global $core; - if ($w->offline) { + if ($w->offline + || ($w->homeonly == 1 && !$core->url->isHome($core->url->type)) + || ($w->homeonly == 2 && $core->url->isHome($core->url->type)) + ) { return null; } - if (($w->homeonly == 1 && !$core->url->isHome($core->url->type)) - || ($w->homeonly == 2 && $core->url->isHome($core->url->type))) { - return null; - } - - $rs = $core->con->select( - 'SELECT COUNT(*) AS count, U.user_id ' . - "FROM " . $core->prefix . "post P " . - 'INNER JOIN ' . $core->prefix . 'user U ON U.user_id = P.user_id ' . - "WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " . - 'AND post_status=1 AND user_status=1 ' . - self::period('post_dt', $w->period) . - 'GROUP BY U.user_id ' . - 'ORDER BY count ' . ($w->sort == 'asc' ? 'ASC' : 'DESC') . ', U.user_id ASC ' . - $core->con->limit(abs((integer) $w->limit))); - - if ($rs->isEmpty()) { - return null; - } - - $content = ''; - $i = 0; - while($rs->fetch()) { - $user = $core->con->select( - "SELECT * FROM " . $core->prefix . "user WHERE user_id='" . $rs->user_id . "' " - ); - - $author = dcUtils::getUserCN( - $user->user_id, - $user->user_name, - $user->user_firstname, - $user->user_displayname - ); - - if (empty($author)) { - continue; - } - - $i++; - $rank = '' . $i . ''; - - $core->blog->settings->addNamespace('authormode'); - if ($core->blog->settings->authormode->authormode_active) { - $author = 'user_id . '" ' . - 'title="' . __('Author posts') . '">' . $author . ''; - } - elseif ($user->user_url) { - $author = '' . $author . ''; - } - $author = '' . $author . ''; - - if ($rs->count == 0) { - $count = __('no entries'); - } else { - $count = sprintf(__('one entry', '%s entries', $rs->count), $rs->count); - } - - $content .= sprintf( - '
  • %s
  • ', - str_replace( - ['%rank%', '%author%', '%count%'], - [$rank, $author, $count], - $w->text - ) - ); - } - - if ($i < 1) { + $lines = topWriter::posts($core, $w->period, $w->limit, $w->sort == 'desc'); + if (empty($lines)) { return null; } @@ -308,35 +161,26 @@ class topWriterWidget 'topentries ' . $w->class, '', ($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') . - sprintf('', $content) + sprintf('', implode('', self::lines($lines, 'posts', $w->text))) ); } - private static function period($t, $p) + private static function lines($lines, $id, $text) { - $pat = '%Y-%m-%d %H:%M:%S'; - switch($p) { - case 'day': - return - "AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24) . "' "; - break; - - case 'week': - return - "AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*7) . "' "; - break; - - case 'month': - return - "AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*30) . "' "; - break; - - case 'year': - return - "AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*30*12) . "' "; - break; + $li = []; + foreach ($lines as $k => $line) { + $rank = '' . $k . ''; + $author = '' . (empty($line['author_link']) ? $line['author'] : $line['author_link']) . ''; + $li[] = sprintf( + '
  • %s
  • ', + str_replace( + ['%rank%', '%author%', '%count%'], + [$rank, $author, $line['count']], + $text + ) + ); } - return ''; + return $li; } -} \ No newline at end of file +} diff --git a/inc/class.topwriter.php b/inc/class.topwriter.php new file mode 100644 index 0000000..1e8d676 --- /dev/null +++ b/inc/class.topwriter.php @@ -0,0 +1,189 @@ +prefix . 'post P ' . + 'INNER JOIN ' . $core->prefix . 'user U ON U.user_id = P.user_id ' . + "WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " . + 'AND post_status=1 AND user_status=1 ' . + self::period('post_dt', $period) . + 'GROUP BY U.user_id ' . + 'ORDER BY count ' . ($sort_desc ? 'DESC' : 'ASC') . ' , U.user_id ASC ' . + $core->con->limit(abs((int) $limit)); + + $rs = $core->con->select($req); + if ($rs->isEmpty()) { + return null; + } + + $core->blog->settings->addNamespace('authormode'); + + $res = []; + $i = 0; + while ($rs->fetch()) { + $user = $core->con->select( + 'SELECT * FROM ' . $core->prefix . "user WHERE user_id='" . $rs->user_id . "' " + ); + if ($user->isEmpty()) { + continue; + } + + $author = dcUtils::getUserCN( + $user->user_id, + $user->user_name, + $user->user_firstname, + $user->user_displayname + ); + if (empty($author)) { + continue; + } + + $i++; + if ($core->blog->settings->authormode->authormode_active) { + $res[$i]['author_link'] = '' . $author . ''; + } elseif ($user->user_url) { + $res[$i]['author_link'] = '' . $author . ''; + } + $res[$i]['author'] = $author; + + if ($rs->count == 0) { + $res[$i]['count'] = __('no entries'); + } else { + $res[$i]['count'] = sprintf(__('one entry', '%s entries', $rs->count), $rs->count); + } + } + + if (!$i) { + return null; + } + + return $res; + } + + public static function comments(dcCore $core, string $period, int $limit, bool $sort_desc = true, $exclude = false) + { + $req = 'SELECT COUNT(*) AS count, comment_email ' . + 'FROM ' . $core->prefix . 'post P, ' . $core->prefix . 'comment C ' . + 'WHERE P.post_id=C.post_id ' . + "AND blog_id='" . $core->con->escape($core->blog->id) . "' " . + 'AND post_status=1 AND comment_status=1 ' . + self::period('comment_dt', $period); + + if ($exclude) { + $req .= 'AND comment_email NOT IN (' . + ' SELECT U.user_email ' . + ' FROM ' . $core->prefix . 'user U' . + ' INNER JOIN ' . $core->prefix . 'post P ON P.user_id = U.user_id ' . + " WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " . + ' GROUP BY U.user_email) '; + } + + $req .= 'GROUP BY comment_email ' . + 'ORDER BY count ' . ($sort_desc ? 'DESC' : 'ASC') . ' ' . + $core->con->limit(abs((int) $limit)); + + $rs = $core->con->select($req); + if ($rs->isEmpty()) { + return null; + } + + $res = []; + $i = 0; + while ($rs->fetch()) { + $user = $core->con->select( + 'SELECT * FROM ' . $core->prefix . 'comment ' . + "WHERE comment_email='" . $rs->comment_email . "' " . + 'ORDER BY comment_dt DESC' + ); + + if (!$user->comment_author) { + continue; + } + + $i++; + + if ($user->comment_site) { + $res[$i]['author_link'] = '' . $user->comment_author . ''; + } + $res[$i]['author'] = $user->comment_author; + + if ($rs->count == 0) { + $res[$i]['count'] = __('no comments'); + } else { + $res[$i]['count'] = sprintf(__('one comment', '%s comments', $rs->count), $rs->count); + } + } + + if (!$i) { + return null; + } + + return $res; + } + + private static function period(string $field, string $period): string + { + $pattern = '%Y-%m-%d %H:%M:%S'; + $time = 0; + switch ($period) { + case 'day': + $time = 3600 * 24; + + break; + + case 'week': + $time = 3600 * 24 * 7; + + break; + + case 'month': + $time = 3600 * 24 * 30; + + break; + + case 'year': + $time = 3600 * 24 * 30 * 12; + + break; + + default: + return ''; + + break; + } + + return "AND $field > TIMESTAMP '" . dt::str($pattern, time() - $time) . "' "; + } + + public static function periods() + { + return [ + __('last day') => 'day', + __('last week') => 'week', + __('last month') => 'month', + __('last year') => 'year', + __('from begining') => '' + ]; + } +} diff --git a/locales/fr/main.po b/locales/fr/main.po index c37adcb..8bac772 100644 --- a/locales/fr/main.po +++ b/locales/fr/main.po @@ -1,69 +1,48 @@ - msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: topWriter 0.8.1\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-09-25T16:39:29+00:00\n" +"PO-Revision-Date: 2021-11-06T20:12:30+00:00\n" "Last-Translator: Jean-Christian Denis\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +msgid "Top writer: entries" +msgstr "Top rédacteur : billets" + msgid "Top writer: comments" msgstr "Top rédacteur : commentaires" +msgid "Period:" +msgstr "Période :" + +msgid "Limit:" +msgstr "Limite :" + msgid "List users who write more comments" msgstr "Liste les utilisateurs qui ont écrit le plus de commentaires" msgid "Top comments" msgstr "Top commentaires" -msgid "Period:" -msgstr "Période :" - -msgid "day" -msgstr "jour" - -msgid "week" -msgstr "semaine" - -msgid "month" -msgstr "mois" - -msgid "year" -msgstr "année" - -msgid "from begining" -msgstr "depuis le début" - -msgid "Limit:" -msgstr "Limite :" - msgid "Exclude post writer from list" msgstr "Exclure de la liste les auteurs de billets" -msgid "Top writer: entries" -msgstr "Top rédacteur : billets" - msgid "List users who write more posts" msgstr "Liste les utilisateurs qui ont écrit le plus de billets" msgid "Top entries" msgstr "Top billets" -msgid "Author link" -msgstr "Lien vers l'auteur" - -msgid "one comment" -msgid_plural "%s comments" -msgstr[0] "un commentaire" -msgstr[1] "%s commentaires" - msgid "Author posts" msgstr "Billets de l'auteur" +msgid "Author link" +msgstr "Lien vers l'auteur" + msgid "no entries" msgstr "aucun billet" @@ -72,6 +51,29 @@ msgid_plural "%s entries" msgstr[0] "une publication" msgstr[1] "%s publications" +msgid "no comments" +msgstr "aucun commentaire" + +msgid "one comment" +msgid_plural "%s comments" +msgstr[0] "un commentaire" +msgstr[1] "%s commentaires" + +msgid "last day" +msgstr "dernier jour" + +msgid "last week" +msgstr "dernière semaine" + +msgid "last month" +msgstr "dernier mois" + +msgid "last year" +msgstr "dernière année" + +msgid "from begining" +msgstr "depuis le début" + msgid "Ranking of the most prolific writers and/or commentators" msgstr "Classement des plus prolifiques rédacteurs et/ou commentateurs"