<?php
/**
* @package Dotclear
* @subpackage Backend
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
if (!defined('DC_RC_PATH')) {
return;
}
class dcPager extends pager
{
protected $form_action;
protected $form_hidden;
/**
* Gets the link.
*
* @param string $li_class The li class
* @param string $href The href
* @param string $img_src The image source
* @param string $img_src_nolink The image source nolink
* @param string $img_alt The image alternate
* @param bool $enable_link The enable link
*
* @return string The link.
*/
protected function getLink($li_class, $href, $img_src, $img_src_nolink, $img_alt, $enable_link)
{
if ($enable_link) {
$formatter = '<li class="%s btn"><a href="%s"><img src="%s" alt="%s"/></a><span class="hidden">%s</span></li>';
return sprintf($formatter, $li_class, $href, $img_src, $img_alt, $img_alt);
}
$formatter = '<li class="%s no-link btn"><img src="%s" alt="%s"/></li>';
return sprintf($formatter, $li_class, $img_src_nolink, $img_alt);
}
/**
* Sets the url.
*/
public function setURL()
{
parent::setURL();
$url = parse_url($_SERVER['REQUEST_URI']);
if (isset($url['query'])) {
parse_str($url['query'], $args);
} else {
$args = [];
}
# Removing session information
if (session_id()) {
if (isset($args[session_name()])) {
unset($args[session_name()]);
}
}
if (isset($args[$this->var_page])) {
unset($args[$this->var_page]);
}
if (isset($args['ok'])) {
unset($args['ok']);
}
$this->form_hidden = '';
foreach ($args as $k => $v) {
// Check parameter key (will prevent some forms of XSS)
if ($k === preg_replace('`[^A-Za-z0-9_-]`', '', $k)) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
$this->form_hidden .= form::hidden([$k . '[]'], html::escapeHTML($v2));
}
} else {
$this->form_hidden .= form::hidden([$k], html::escapeHTML($v));
}
}
}
$this->form_action = $url['path'];
}
/**
* Pager Links
*
* Returns pager links
*
* @return string
*/
public function getLinks()
{
$this->setURL();
$htmlFirst = $this->getLink(
'first',
sprintf($this->page_url, 1),
'images/pagination/first.svg',
'images/pagination/no-first.svg',
__('First page'),
($this->env > 1)
);
$htmlPrev = $this->getLink(
'prev',
sprintf($this->page_url, $this->env - 1),
'images/pagination/previous.svg',
'images/pagination/no-previous.svg',
__('Previous page'),
($this->env > 1)
);
$htmlNext = $this->getLink(
'next',
sprintf($this->page_url, $this->env + 1),
'images/pagination/next.svg',
'images/pagination/no-next.svg',
__('Next page'),
($this->env < $this->nb_pages)
);
$htmlLast = $this->getLink(
'last',
sprintf($this->page_url, $this->nb_pages),
'images/pagination/last.svg',
'images/pagination/no-last.svg',
__('Last page'),
($this->env < $this->nb_pages)
);
$htmlCurrent = '<li class="active"><strong>' .
sprintf(__('Page %s / %s'), $this->env, $this->nb_pages) .
'</strong></li>';
$htmlDirect = ($this->nb_pages > 1 ?
sprintf(
'<li class="direct-access">' . __('Direct access page %s'),
form::number([$this->var_page], 1, $this->nb_pages)
) .
'<input type="submit" value="' . __('ok') . '" class="reset" ' .
'name="ok" />' . $this->form_hidden . '</li>' : '');
$res = '<form action="' . $this->form_action . '" method="get">' .
'<div class="pager"><ul>' .
$htmlFirst .
$htmlPrev .
$htmlCurrent .
$htmlNext .
$htmlLast .
$htmlDirect .
'</ul>' .
'</div>' .
'</form>'
;
return $this->nb_elements > 0 ? $res : '';
}
}
class adminGenericList
{
protected $core;
protected $rs;
protected $rs_count;
protected $html_prev;
protected $html_next;
/**
* Constructs a new instance.
*
* @param dcCore $core The core
* @param record $rs The record
* @param mixed $rs_count The rs count
*/
public function __construct(dcCore $core, $rs, $rs_count)
{
$this->core = &$core;
$this->rs = &$rs;
$this->rs_count = $rs_count;
$this->html_prev = __('« prev.');
$this->html_next = __('next »');
}
/**
* Get user defined columns
*
* @param string $type The type
* @param array|ArrayObject $cols The columns
*/
public function userColumns($type, $cols)
{
$cols = adminUserPref::getUserColumns($type, $cols);
}
}
class adminPostList extends adminGenericList
{
/**
* Display admin post list
*
* @param integer $page The page
* @param integer $nb_per_page The number of per page
* @param string $enclose_block The enclose block
* @param bool $filter The filter
*/
public function display($page, $nb_per_page, $enclose_block = '', $filter = false)
{
if ($this->rs->isEmpty()) {
if ($filter) {
echo '<p><strong>' . __('No entry matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No entry') . '</strong></p>';
}
} else {
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$entries = [];
if (isset($_REQUEST['entries'])) {
foreach ($_REQUEST['entries'] as $v) {
$entries[(int) $v] = true;
}
}
$html_block = '<div class="table-outer">' .
'<table>';
if ($filter) {
$html_block .= '<caption>' . sprintf(__('List of %s entries matching the filter.'), $this->rs_count) . '</caption>';
} else {
$nb_published = $this->core->blog->getPosts(['post_status' => 1], true)->f(0);
$nb_pending = $this->core->blog->getPosts(['post_status' => -2], true)->f(0);
$nb_programmed = $this->core->blog->getPosts(['post_status' => -1], true)->f(0);
$nb_unpublished = $this->core->blog->getPosts(['post_status' => 0], true)->f(0);
$html_block .= '<caption>' .
sprintf(__('List of entries (%s)'), $this->rs_count) .
($nb_published ?
sprintf(
__(', <a href="%s">published</a> (1)', ', <a href="%s">published</a> (%s)', $nb_published),
$this->core->adminurl->get('admin.posts', ['status' => 1]),
$nb_published
) : '') .
($nb_pending ?
sprintf(
__(', <a href="%s">pending</a> (1)', ', <a href="%s">pending</a> (%s)', $nb_pending),
$this->core->adminurl->get('admin.posts', ['status' => -2]),
$nb_pending
) : '') .
($nb_programmed ?
sprintf(
__(', <a href="%s">programmed</a> (1)', ', <a href="%s">programmed</a> (%s)', $nb_programmed),
$this->core->adminurl->get('admin.posts', ['status' => -1]),
$nb_programmed
) : '') .
($nb_unpublished ?
sprintf(
__(', <a href="%s">unpublished</a> (1)', ', <a href="%s">unpublished</a> (%s)', $nb_unpublished),
$this->core->adminurl->get('admin.posts', ['status' => 0]),
$nb_unpublished
) : '') .
'</caption>';
}
$cols = [
'title' => '<th colspan="2" class="first">' . __('Title') . '</th>',
'date' => '<th scope="col">' . __('Date') . '</th>',
'category' => '<th scope="col">' . __('Category') . '</th>',
'author' => '<th scope="col">' . __('Author') . '</th>',
'comments' => '<th scope="col"><img src="images/comments.png" alt="" title="' . __('Comments') .
'" /><span class="hidden">' . __('Comments') . '</span></th>',
'trackbacks' => '<th scope="col"><img src="images/trackbacks.png" alt="" title="' . __('Trackbacks') .
'" /><span class="hidden">' . __('Trackbacks') . '</span></th>',
'status' => '<th scope="col">' . __('Status') . '</th>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminPostListHeader', $this->core, $this->rs, $cols);
// Cope with optional columns
$this->userColumns('posts', $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
echo $pager->getLinks();
$blocks = explode('%s', $html_block);
echo $blocks[0];
while ($this->rs->fetch()) {
echo $this->postLine(isset($entries[$this->rs->post_id]));
}
echo $blocks[1];
$fmt = fn ($title, $image) => sprintf('<img alt="%1$s" title="%1$s" src="images/%2$s" /> %1$s', $title, $image);
echo '<p class="info">' . __('Legend: ') .
$fmt(__('Published'), 'check-on.png') . ' - ' .
$fmt(__('Unpublished'), 'check-off.png') . ' - ' .
$fmt(__('Scheduled'), 'scheduled.png') . ' - ' .
$fmt(__('Pending'), 'check-wrn.png') . ' - ' .
$fmt(__('Protected'), 'locker.png') . ' - ' .
$fmt(__('Selected'), 'selected.png') . ' - ' .
$fmt(__('Attachments'), 'attach.png') .
'</p>';
echo $blocks[2];
echo $pager->getLinks();
}
}
/**
* Get a line.
*
* @param bool $checked The checked flag
*
* @return string
*/
private function postLine($checked)
{
if ($this->core->auth->check('categories', $this->core->blog->id)) {
$cat_link = '<a href="' . $this->core->adminurl->get('admin.category', ['id' => '%s'], '&', true) . '">%s</a>';
} else {
$cat_link = '%2$s';
}
if ($this->rs->cat_title) {
$cat_title = sprintf(
$cat_link,
$this->rs->cat_id,
html::escapeHTML($this->rs->cat_title)
);
} else {
$cat_title = __('(No cat)');
}
$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" class="mark mark-%3$s" />';
$img_status = '';
$sts_class = '';
switch ($this->rs->post_status) {
case 1:
$img_status = sprintf($img, __('Published'), 'check-on.png', 'published');
$sts_class = 'sts-online';
break;
case 0:
$img_status = sprintf($img, __('Unpublished'), 'check-off.png', 'unpublished');
$sts_class = 'sts-offline';
break;
case -1:
$img_status = sprintf($img, __('Scheduled'), 'scheduled.png', 'scheduled');
$sts_class = 'sts-scheduled';
break;
case -2:
$img_status = sprintf($img, __('Pending'), 'check-wrn.png', 'pending');
$sts_class = 'sts-pending';
break;
}
$protected = '';
if ($this->rs->post_password) {
$protected = sprintf($img, __('Protected'), 'locker.png', 'locked');
}
$selected = '';
if ($this->rs->post_selected) {
$selected = sprintf($img, __('Selected'), 'selected.png', 'selected');
}
$attach = '';
$nb_media = $this->rs->countMedia();
if ($nb_media > 0) {
$attach_str = $nb_media == 1 ? __('%d attachment') : __('%d attachments');
$attach = sprintf($img, sprintf($attach_str, $nb_media), 'attach.png', 'attach');
}
$res = '<tr class="line ' . ($this->rs->post_status != 1 ? 'offline ' : '') . $sts_class . '"' .
' id="p' . $this->rs->post_id . '">';
$cols = [
'check' => '<td class="nowrap">' .
form::checkbox(
['entries[]'],
$this->rs->post_id,
[
'checked' => $checked,
'disabled' => !$this->rs->isEditable(),
]
) .
'</td>',
'title' => '<td class="maximal" scope="row"><a href="' .
$this->core->getPostAdminURL($this->rs->post_type, $this->rs->post_id) . '">' .
html::escapeHTML(trim(html::clean($this->rs->post_title))) . '</a></td>',
'date' => '<td class="nowrap count">' . dt::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->post_dt) . '</td>',
'category' => '<td class="nowrap">' . $cat_title . '</td>',
'author' => '<td class="nowrap">' . html::escapeHTML($this->rs->user_id) . '</td>',
'comments' => '<td class="nowrap count">' . $this->rs->nb_comment . '</td>',
'trackbacks' => '<td class="nowrap count">' . $this->rs->nb_trackback . '</td>',
'status' => '<td class="nowrap status">' . $img_status . ' ' . $selected . ' ' . $protected . ' ' . $attach . '</td>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminPostListValue', $this->core, $this->rs, $cols);
// Cope with optional columns
$this->userColumns('posts', $cols);
$res .= implode(iterator_to_array($cols));
$res .= '</tr>';
return $res;
}
}
class adminPostMiniList extends adminGenericList
{
/**
* Display a mini post list
*
* @param integer $page The page
* @param integer $nb_per_page The number of per page
* @param string $enclose_block The enclose block
*/
public function display($page, $nb_per_page, $enclose_block = '')
{
if ($this->rs->isEmpty()) {
echo '<p><strong>' . __('No entry') . '</strong></p>';
} else {
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$html_block = '<div class="table-outer clear">' .
'<table><caption class="hidden">' . __('Entries list') . '</caption><tr>';
$cols = [
'title' => '<th scope="col">' . __('Title') . '</th>',
'date' => '<th scope="col">' . __('Date') . '</th>',
'author' => '<th scope="col">' . __('Author') . '</th>',
'status' => '<th scope="col">' . __('Status') . '</th>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminPostMiniListHeader', $this->core, $this->rs, $cols);
// Cope with optional columns
$this->userColumns('posts', $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table></div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
echo $pager->getLinks();
$blocks = explode('%s', $html_block);
echo $blocks[0];
while ($this->rs->fetch()) {
echo $this->postLine();
}
echo $blocks[1];
echo $pager->getLinks();
}
}
/**
* Get a line.
*
* @return string
*/
private function postLine()
{
$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
$img_status = '';
$sts_class = '';
switch ($this->rs->post_status) {
case 1:
$img_status = sprintf($img, __('Published'), 'check-on.png');
$sts_class = 'sts-online';
break;
case 0:
$img_status = sprintf($img, __('Unpublished'), 'check-off.png');
$sts_class = 'sts-offline';
break;
case -1:
$img_status = sprintf($img, __('Scheduled'), 'scheduled.png');
$sts_class = 'sts-scheduled';
break;
case -2:
$img_status = sprintf($img, __('Pending'), 'check-wrn.png');
$sts_class = 'sts-pending';
break;
}
$protected = '';
if ($this->rs->post_password) {
$protected = sprintf($img, __('Protected'), 'locker.png');
}
$selected = '';
if ($this->rs->post_selected) {
$selected = sprintf($img, __('Selected'), 'selected.png');
}
$attach = '';
$nb_media = $this->rs->countMedia();
if ($nb_media > 0) {
$attach_str = $nb_media == 1 ? __('%d attachment') : __('%d attachments');
$attach = sprintf($img, sprintf($attach_str, $nb_media), 'attach.png');
}
$res = '<tr class="line ' . ($this->rs->post_status != 1 ? 'offline ' : '') . $sts_class . '"' .
' id="p' . $this->rs->post_id . '">';
$cols = [
'title' => '<td scope="row" class="maximal"><a href="' .
$this->core->getPostAdminURL($this->rs->post_type, $this->rs->post_id) . '" ' .
'title="' . html::escapeHTML($this->rs->getURL()) . '">' .
html::escapeHTML(trim(html::clean($this->rs->post_title))) . '</a></td>',
'date' => '<td class="nowrap count">' . dt::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->post_dt) . '</td>',
'author' => '<td class="nowrap">' . html::escapeHTML($this->rs->user_id) . '</td>',
'status' => '<td class="nowrap status">' . $img_status . ' ' . $selected . ' ' . $protected . ' ' . $attach . '</td>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminPostMiniListValue', $this->core, $this->rs, $cols);
// Cope with optional columns
$this->userColumns('posts', $cols);
$res .= implode(iterator_to_array($cols));
$res .= '</tr>';
return $res;
}
}
class adminCommentList extends adminGenericList
{
/**
* Display a comment list
*
* @param integer $page The page
* @param integer $nb_per_page The number of per page
* @param string $enclose_block The enclose block
* @param bool $filter The filter flag
* @param bool $spam The spam flag
* @param bool $show_ip The show ip flag
*/
public function display($page, $nb_per_page, $enclose_block = '', $filter = false, $spam = false, $show_ip = true)
{
if ($this->rs->isEmpty()) {
if ($filter) {
echo '<p><strong>' . __('No comments or trackbacks matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No comments') . '</strong></p>';
}
} else {
// Get antispam filters' name
$filters = [];
if ($spam) {
if (class_exists('dcAntispam')) {
dcAntispam::initFilters();
$fs = dcAntispam::$filters->getFilters();
foreach ($fs as $fid => $f) {
$filters[$fid] = $f->name;
}
}
}
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$comments = [];
if (isset($_REQUEST['comments'])) {
foreach ($_REQUEST['comments'] as $v) {
$comments[(int) $v] = true;
}
}
$html_block = '<div class="table-outer">' .
'<table>';
if ($filter) {
$html_block .= '<caption>' .
sprintf(__(
'Comment or trackback matching the filter.',
'List of %s comments or trackbacks matching the filter.',
$this->rs_count
), $this->rs_count) .
'</caption>';
} else {
$nb_published = $this->core->blog->getComments(['comment_status' => 1], true)->f(0);
$nb_spam = $this->core->blog->getComments(['comment_status' => -2], true)->f(0);
$nb_pending = $this->core->blog->getComments(['comment_status' => -1], true)->f(0);
$nb_unpublished = $this->core->blog->getComments(['comment_status' => 0], true)->f(0);
$html_block .= '<caption>' .
sprintf(__('List of comments and trackbacks (%s)'), $this->rs_count) .
($nb_published ?
sprintf(
__(', <a href="%s">published</a> (1)', ', <a href="%s">published</a> (%s)', $nb_published),
$this->core->adminurl->get('admin.comments', ['status' => 1]),
$nb_published
) : '') .
($nb_spam ?
sprintf(
__(', <a href="%s">spam</a> (1)', ', <a href="%s">spam</a> (%s)', $nb_spam),
$this->core->adminurl->get('admin.comments', ['status' => -2]),
$nb_spam
) : '') .
($nb_pending ?
sprintf(
__(', <a href="%s">pending</a> (1)', ', <a href="%s">pending</a> (%s)', $nb_pending),
$this->core->adminurl->get('admin.comments', ['status' => -1]),
$nb_pending
) : '') .
($nb_unpublished ?
sprintf(
__(', <a href="%s">unpublished</a> (1)', ', <a href="%s">unpublished</a> (%s)', $nb_unpublished),
$this->core->adminurl->get('admin.comments', ['status' => 0]),
$nb_unpublished
) : '') .
'</caption>';
}
$cols = [
'type' => '<th colspan="2" scope="col" abbr="comm" class="first">' . __('Type') . '</th>',
'author' => '<th scope="col">' . __('Author') . '</th>',
'date' => '<th scope="col">' . __('Date') . '</th>',
'status' => '<th scope="col" class="txt-center">' . __('Status') . '</th>',
];
if ($spam) {
$cols['ip'] = '<th scope="col">' . __('IP') . '</th>';
$cols['spam_filter'] = '<th scope="col">' . __('Spam filter') . '</th>';
}
$cols['entry'] = '<th scope="col" abbr="entry">' . __('Entry') . '</th>';
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminCommentListHeader', $this->core, $this->rs, $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
echo $pager->getLinks();
$blocks = explode('%s', $html_block);
echo $blocks[0];
while ($this->rs->fetch()) {
echo $this->commentLine(isset($comments[$this->rs->comment_id]), $spam, $filters);
}
echo $blocks[1];
$fmt = fn ($title, $image) => sprintf('<img alt="%1$s" title="%1$s" src="images/%2$s" /> %1$s', $title, $image);
echo '<p class="info">' . __('Legend: ') .
$fmt(__('Published'), 'check-on.png') . ' - ' .
$fmt(__('Unpublished'), 'check-off.png') . ' - ' .
$fmt(__('Pending'), 'check-wrn.png') . ' - ' .
$fmt(__('Junk'), 'junk.png') .
'</p>';
echo $blocks[2];
echo $pager->getLinks();
}
}
/**
* Get a comment line
*
* @param bool $checked The checked flag
* @param bool $spam The spam flag
* @param array $filters The filters
*
* @return string
*/
private function commentLine($checked = false, $spam = false, $filters = [])
{
global $author, $status, $sortby, $order, $nb;
$author_url = $this->core->adminurl->get('admin.comments', [
'nb' => $nb,
'status' => $status,
'sortby' => $sortby,
'order' => $order,
'author' => $this->rs->comment_author,
]);
$post_url = $this->core->getPostAdminURL($this->rs->post_type, $this->rs->post_id);
$comment_url = $this->core->adminurl->get('admin.comment', ['id' => $this->rs->comment_id]);
$comment_dt = dt::dt2str($this->core->blog->settings->system->date_format . ' - ' .
$this->core->blog->settings->system->time_format, $this->rs->comment_dt);
$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
$img_status = '';
$sts_class = '';
switch ($this->rs->comment_status) {
case 1:
$img_status = sprintf($img, __('Published'), 'check-on.png');
$sts_class = 'sts-online';
break;
case 0:
$img_status = sprintf($img, __('Unpublished'), 'check-off.png');
$sts_class = 'sts-offline';
break;
case -1:
$img_status = sprintf($img, __('Pending'), 'check-wrn.png');
$sts_class = 'sts-pending';
break;
case -2:
$img_status = sprintf($img, __('Junk'), 'junk.png');
$sts_class = 'sts-junk';
break;
}
$post_title = html::escapeHTML(trim(html::clean($this->rs->post_title)));
if (mb_strlen($post_title) > 70) {
$post_title = mb_strcut($post_title, 0, 67) . '...';
}
$comment_title = sprintf(
__('Edit the %1$s from %2$s'),
$this->rs->comment_trackback ? __('trackback') : __('comment'),
html::escapeHTML($this->rs->comment_author)
);
$res = '<tr class="line ' . ($this->rs->comment_status != 1 ? 'offline ' : '') . $sts_class . '"' .
' id="c' . $this->rs->comment_id . '">';
$cols = [
'check' => '<td class="nowrap">' .
form::checkbox(['comments[]'], $this->rs->comment_id, $checked) .
'</td>',
'type' => '<td class="nowrap" abbr="' . __('Type and author') . '" scope="row">' .
'<a href="' . $comment_url . '" title="' . $comment_title . '">' .
'<img src="images/edit-mini.png" alt="' . __('Edit') . '"/> ' .
($this->rs->comment_trackback ? __('trackback') : __('comment')) . ' ' . '</a></td>',
'author' => '<td class="nowrap maximal"><a href="' . $author_url . '">' .
html::escapeHTML($this->rs->comment_author) . '</a></td>',
'date' => '<td class="nowrap count">' . dt::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->comment_dt) . '</td>',
'status' => '<td class="nowrap status txt-center">' . $img_status . '</td>',
];
if ($spam) {
$filter_name = '';
if ($this->rs->comment_spam_filter) {
if (isset($filters[$this->rs->comment_spam_filter])) {
$filter_name = $filters[$this->rs->comment_spam_filter];
} else {
$filter_name = $this->rs->comment_spam_filter;
}
}
$cols['ip'] = '<td class="nowrap"><a href="' .
$this->core->adminurl->get('admin.comments', ['ip' => $this->rs->comment_ip]) . '">' .
$this->rs->comment_ip . '</a></td>';
$cols['spam_filter'] = '<td class="nowrap">' . $filter_name . '</td>';
}
$cols['entry'] = '<td class="nowrap discrete"><a href="' . $post_url . '">' . $post_title . '</a>' .
($this->rs->post_type != 'post' ? ' (' . html::escapeHTML($this->rs->post_type) . ')' : '') . '</td>';
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminCommentListValue', $this->core, $this->rs, $cols);
$res .= implode(iterator_to_array($cols));
$res .= '</tr>';
return $res;
}
}
class adminBlogList extends adminGenericList
{
/**
* Display a blog list
*
* @param integer $page The page
* @param integer $nb_per_page The number of per page
* @param string $enclose_block The enclose block
* @param bool $filter The filter flag
*/
public function display($page, $nb_per_page, $enclose_block = '', $filter = false)
{
if ($this->rs->isEmpty()) {
if ($filter) {
echo '<p><strong>' . __('No blog matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No blog') . '</strong></p>';
}
} else {
$blogs = [];
if (isset($_REQUEST['blogs'])) {
foreach ($_REQUEST['blogs'] as $v) {
$blogs[$v] = true;
}
}
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$cols = [
'blog' => '<th' .
($this->core->auth->isSuperAdmin() ? ' colspan="2"' : '') .
' scope="col" abbr="comm" class="first nowrap">' . __('Blog id') . '</th>',
'name' => '<th scope="col" abbr="name">' . __('Blog name') . '</th>',
'url' => '<th scope="col" class="nowrap">' . __('URL') . '</th>',
'posts' => '<th scope="col" class="nowrap">' . __('Entries (all types)') . '</th>',
'upddt' => '<th scope="col" class="nowrap">' . __('Last update') . '</th>',
'status' => '<th scope="col" class="txt-center">' . __('Status') . '</th>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminBlogListHeader', $this->core, $this->rs, $cols);
$html_block = '<div class="table-outer"><table>' .
(
$filter ?
'<caption>' .
sprintf(__('%d blog matches the filter.', '%d blogs match the filter.', $this->rs_count), $this->rs_count) .
'</caption>'
:
'<caption class="hidden">' . __('Blogs list') . '</caption>'
) .
'<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks();
echo $blocks[0];
while ($this->rs->fetch()) {
echo $this->blogLine(isset($blogs[$this->rs->blog_id]));
}
echo $blocks[1];
$fmt = fn ($title, $image) => sprintf('<img alt="%1$s" title="%1$s" src="images/%2$s" /> %1$s', $title, $image);
echo '<p class="info">' . __('Legend: ') .
$fmt(__('online'), 'check-on.png') . ' - ' .
$fmt(__('offline'), 'check-off.png') . ' - ' .
$fmt(__('removed'), 'check-wrn.png') .
'</p>';
echo $blocks[2];
echo $pager->getLinks();
}
}
/**
* Get a blog line
*
* @param bool $checked The checked flag
*
* @return string
*/
private function blogLine($checked = false)
{
$blog_id = html::escapeHTML($this->rs->blog_id);
$cols = [
'check' => ($this->core->auth->isSuperAdmin() ?
'<td class="nowrap">' .
form::checkbox(['blogs[]'], $this->rs->blog_id, $checked) .
'</td>' : ''),
'blog' => '<td class="nowrap">' .
($this->core->auth->isSuperAdmin() ?
'<a href="' . $this->core->adminurl->get('admin.blog', ['id' => $blog_id]) . '" ' .
'title="' . sprintf(__('Edit blog settings for %s'), $blog_id) . '">' .
'<img src="images/edit-mini.png" alt="' . __('Edit blog settings') . '" /> ' . $blog_id . '</a> ' :
$blog_id . ' ') .
'</td>',
'name' => '<td class="maximal">' .
'<a href="' . $this->core->adminurl->get('admin.home', ['switchblog' => $this->rs->blog_id]) . '" ' .
'title="' . sprintf(__('Switch to blog %s'), $this->rs->blog_id) . '">' .
html::escapeHTML($this->rs->blog_name) . '</a>' .
'</td>',
'url' => '<td class="nowrap">' .
'<a class="outgoing" href="' .
html::escapeHTML($this->rs->blog_url) . '">' . html::escapeHTML($this->rs->blog_url) .
' <img src="images/outgoing-link.svg" alt="" /></a></td>',
'posts' => '<td class="nowrap count">' .
$this->core->countBlogPosts($this->rs->blog_id) .
'</td>',
'upddt' => '<td class="nowrap count">' .
dt::str(__('%Y-%m-%d %H:%M'), strtotime($this->rs->blog_upddt) + dt::getTimeOffset($this->core->auth->getInfo('user_tz'))) .
'</td>',
'status' => '<td class="nowrap status txt-center">' .
sprintf(
'<img src="images/%1$s.png" alt="%2$s" title="%2$s" />',
($this->rs->blog_status == 1 ? 'check-on' : ($this->rs->blog_status == 0 ? 'check-off' : 'check-wrn')),
$this->core->getBlogStatus($this->rs->blog_status)
) .
'</td>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminBlogListValue', $this->core, $this->rs, $cols);
return
'<tr class="line" id="b' . $blog_id . '">' .
implode(iterator_to_array($cols)) .
'</tr>';
}
}
class adminUserList extends adminGenericList
{
/**
* Display a user list
*
* @param integer $page The page
* @param integer $nb_per_page The number of per page
* @param string $enclose_block The enclose block
* @param bool $filter The filter flag
*/
public function display($page, $nb_per_page, $enclose_block = '', $filter = false)
{
if ($this->rs->isEmpty()) {
if ($filter) {
echo '<p><strong>' . __('No user matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No user') . '</strong></p>';
}
} else {
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$html_block = '<div class="table-outer clear">' .
'<table>';
if ($filter) {
$html_block .= '<caption>' . sprintf(__('List of %s users match the filter.'), $this->rs_count) . '</caption>';
} else {
$html_block .= '<caption class="hidden">' . __('Users list') . '</caption>';
}
$cols = [
'username' => '<th colspan="2" scope="col" class="first">' . __('Username') . '</th>',
'first_name' => '<th scope="col">' . __('First Name') . '</th>',
'last_name' => '<th scope="col">' . __('Last Name') . '</th>',
'display_name' => '<th scope="col">' . __('Display name') . '</th>',
'entries' => '<th scope="col" class="nowrap">' . __('Entries (all types)') . '</th>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminUserListHeader', $this->core, $this->rs, $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
echo $pager->getLinks();
$blocks = explode('%s', $html_block);
echo $blocks[0];
while ($this->rs->fetch()) {
echo $this->userLine();
}
echo $blocks[1];
$fmt = fn ($title, $image) => sprintf('<img alt="%1$s" title="%1$s" src="images/%2$s" /> %1$s', $title, $image);
echo '<p class="info">' . __('Legend: ') .
$fmt(__('admin'), 'admin.png') . ' - ' .
$fmt(__('superadmin'), 'superadmin.png') .
'</p>';
echo $blocks[2];
echo $pager->getLinks();
}
}
/**
* Get a user line
*
* @return string
*/
private function userLine()
{
$img = '<img alt="%1$s" title="%1$s" src="images/%2$s" />';
$img_status = '';
$p = $this->core->getUserPermissions($this->rs->user_id);
if (isset($p[$this->core->blog->id]['p']['admin'])) {
$img_status = sprintf($img, __('admin'), 'admin.png');
}
if ($this->rs->user_super) {
$img_status = sprintf($img, __('superadmin'), 'superadmin.png');
}
$res = '<tr class="line">';
$cols = [
'check' => '<td class="nowrap">' . form::hidden(['nb_post[]'], (int) $this->rs->nb_post) .
form::checkbox(['users[]'], $this->rs->user_id) . '</td>',
'username' => '<td class="maximal" scope="row"><a href="' .
$this->core->adminurl->get('admin.user', ['id' => $this->rs->user_id]) . '">' .
$this->rs->user_id . '</a> ' . $img_status . '</td>',
'first_name' => '<td class="nowrap">' . html::escapeHTML($this->rs->user_firstname) . '</td>',
'last_name' => '<td class="nowrap">' . html::escapeHTML($this->rs->user_name) . '</td>',
'display_name' => '<td class="nowrap">' . html::escapeHTML($this->rs->user_displayname) . '</td>',
'entries' => '<td class="nowrap count"><a href="' .
$this->core->adminurl->get('admin.posts', ['user_id' => $this->rs->user_id]) . '">' .
$this->rs->nb_post . '</a></td>',
];
$cols = new ArrayObject($cols);
$this->core->callBehavior('adminUserListValue', $this->core, $this->rs, $cols);
$res .= implode(iterator_to_array($cols));
$res .= '</tr>';
return $res;
}
}
class adminMediaList extends adminGenericList
{
/**
* Display a media list
*
* @param adminMediaFilter $filters The filters
* @param string $enclose_block The enclose block
*/
public function display($filters, $enclose_block = '', $query = false, $page_adminurl = 'admin.media')
{
$nb_items = $this->rs_count - ($filters->d ? 1 : 0);
$nb_folders = $filters->d ? -1 : 0;
if ($filters->q && !$query) {
echo '<p><strong>' . __('No file matches the filter') . '</strong></p>';
} elseif ($nb_items < 1) {
echo '<p><strong>' . __('No file.') . '</strong></p>';
}
if ($this->rs_count && !($filters->q && !$query)) {
$pager = new dcPager($filters->page, $this->rs_count, $filters->nb, 10);
$items = $this->rs->rows();
foreach ($items as $item) {
if ($item->d) {
$nb_folders++;
}
}
$nb_files = $nb_items - $nb_folders;
if ($filters->show() && $query) {
$caption = sprintf(__('%d file matches the filter.', '%d files match the filter.', $nb_items), $nb_items);
} else {
$caption = ($nb_files && $nb_folders ?
sprintf(__('Nb of items: %d → %d folder(s) + %d file(s)'), $nb_items, $nb_folders, $nb_files) :
sprintf(__('Nb of items: %d'), $nb_items));
}
$group = ['dirs' => [], 'files' => []];
for ($i = $pager->index_start, $j = 0; $i <= $pager->index_end; $i++, $j++) {
$group[$items[$i]->d ? 'dirs' : 'files'][] = $this->mediaLine($this->core, $filters, $items[$i], $j, $query, $page_adminurl);
}
if ($filters->file_mode == 'list') {
$table = sprintf(
'<div class="table-outer">' .
'<table class="media-items-bloc">' .
'<caption>' . $caption . '</caption>' .
'<tr>' .
'<th colspan="2" class="first">' . __('Name') . '</th>' .
'<th scope="col">' . __('Date') . '</th>' .
'<th scope="col">' . __('Size') . '</th>' .
'</tr>%s%s</table></div>',
implode($group['dirs']),
implode($group['files'])
);
$html_block = sprintf($enclose_block, $table, '');
} else {
$html_block = sprintf(
'%s%s<div class="media-stats"><p class="form-stats">' . $caption . '</p></div>',
!empty($group['dirs']) ? '<div class="folders-group">' . implode($group['dirs']) . '</div>' : '',
sprintf($enclose_block, '<div class="media-items-bloc">' . implode($group['files']), '') . '</div>'
);
}
echo $pager->getLinks();
echo $html_block;
echo $pager->getLinks();
}
}
public static function mediaLine($core, $filters, $f, $i, $query = false, $page_adminurl = 'admin.media')
{
$fname = $f->basename;
$file = $query ? $f->relname : $f->basename;
$class = 'media-item-bloc'; // cope with js message for grid AND list
$class .= $filters->file_mode == 'list' ? '' : ' media-item media-col-' . ($i % 2);
if ($f->d) {
// Folder
$link = $core->adminurl->get('admin.media', array_merge($filters->values(), ['d' => html::sanitizeURL($f->relname)]));
if ($f->parent) {
$fname = '..';
$class .= ' media-folder-up';
} else {
$class .= ' media-folder';
}
} else {
// Item
$params = new ArrayObject(array_merge($filters->values(), ['id' => $f->media_id]));
$core->callBehavior('adminMediaURLParams', $params);
$link = $core->adminurl->get('admin.media.item', (array) $params);
if ($f->media_priv) {
$class .= ' media-private';
}
}
$maxchars = 34; // cope with design
if (strlen($fname) > $maxchars) {
$fname = substr($fname, 0, $maxchars - 4) . '...' . ($f->d ? '' : files::getExtension($fname));
}
$act = '';
if (!$f->d) {
if ($filters->select > 0) {
if ($filters->select == 1) {
// Single media selection button
$act .= '<a href="' . $link . '"><img src="images/plus.png" alt="' . __('Select this file') . '" ' .
'title="' . __('Select this file') . '" /></a> ';
} else {
// Multiple media selection checkbox
$act .= form::checkbox(['medias[]', 'media_' . rawurlencode($file)], $file);
}
} else {
// Item
if ($filters->post_id) {
// Media attachment button
$act .= '<a class="attach-media" title="' . __('Attach this file to entry') . '" href="' .
$core->adminurl->get(
'admin.post.media',
['media_id' => $f->media_id, 'post_id' => $filters->post_id, 'attach' => 1, 'link_type' => $filters->link_type]
) .
'">' .
'<img src="images/plus.png" alt="' . __('Attach this file to entry') . '"/>' .
'</a>';
}
if ($filters->popup) {
// Media insertion button
$act .= '<a href="' . $link . '"><img src="images/plus.png" alt="' . __('Insert this file into entry') . '" ' .
'title="' . __('Insert this file into entry') . '" /></a> ';
}
}
}
if ($f->del) {
// Deletion button or checkbox
if (!$filters->popup && !$f->d) {
if ($filters->select < 2) {
// Already set for multiple media selection
$act .= form::checkbox(['medias[]', 'media_' . rawurlencode($file)], $file);
}
} else {
$act .= '<a class="media-remove" ' .
'href="' . $core->adminurl->get($page_adminurl, array_merge($filters->values(), ['remove' => rawurlencode($file)])) . '">' .
'<img src="images/trash.png" alt="' . __('Delete') . '" title="' . __('delete') . '" /></a>';
}
}
$file_type = explode('/', (string) $f->type);
$class_open = 'class="modal-' . $file_type[0] . '" ';
// Render markup
if ($filters->file_mode != 'list') {
$res = '<div class="' . $class . '"><p><a class="media-icon media-link" href="' . rawurldecode($link) . '">' .
'<img class="media-icon-square" src="' . $f->media_icon . '" alt="" />' . ($query ? $file : $fname) . '</a></p>';
$lst = '';
if (!$f->d) {
$lst .= '<li>' . ($f->media_priv ? '<img class="media-private" src="images/locker.png" alt="' . __('private media') . '">' : '') . $f->media_title . '</li>' .
'<li>' .
$f->media_dtstr . ' - ' .
files::size($f->size) . ' - ' .
'<a ' . $class_open . 'href="' . $f->file_url . '">' . __('open') . '</a>' .
'</li>';
}
$lst .= ($act != '' ? '<li class="media-action"> ' . $act . '</li>' : '');
// Show player if relevant
if ($file_type[0] == 'audio') {
$lst .= '<li>' . dcMedia::audioPlayer($f->type, $f->file_url, null, null, false, false) . '</li>';
}
$res .= ($lst != '' ? '<ul>' . $lst . '</ul>' : '');
$res .= '</div>';
} else {
$res = '<tr class="' . $class . '">';
$res .= '<td class="media-action">' . $act . '</td>';
$res .= '<td class="maximal" scope="row"><a class="media-flag media-link" href="' . rawurldecode($link) . '">' .
'<img class="media-icon-square" src="' . $f->media_icon . '" alt="" />' . ($query ? $file : $fname) . '</a>' .
'<br />' . ($f->d ? '' : ($f->media_priv ? '<img class="media-private" src="images/locker.png" alt="' . __('private media') . '">' : '') . $f->media_title) . '</td>';
$res .= '<td class="nowrap count">' . ($f->d ? '' : $f->media_dtstr) . '</td>';
$res .= '<td class="nowrap count">' . ($f->d ? '' : files::size($f->size) . ' - ' .
'<a ' . $class_open . 'href="' . $f->file_url . '">' . __('open') . '</a>') . '</td>';
$res .= '</tr>';
}
return $res;
}
}