Seditio Source
Root |
./othercms/dotclear-2.22/inc/admin/class.dc.favorites.php
<?php
/**
 * @package Dotclear
 * @subpackage Backend
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright GPL-2.0-only
 */
if (!defined('DC_RC_PATH')) {
    return;
}

/**
 * dcFavorites -- Favorites handling facilities
 */
class dcFavorites
{
   
/** @var dcCore dotclear core instance */
   
protected $core;

   
/** @var ArrayObject list of favorite definitions  */
   
protected $fav_defs;

   
/** @var dcWorkspace current favorite landing workspace */
   
protected $ws;

   
/** @var array list of user-defined favorite ids */
   
protected $local_prefs;

   
/** @var array list of globally-defined favorite ids */
   
protected $global_prefs;

   
/** @var array list of user preferences (either one of the 2 above, or not!) */
   
protected $user_prefs;

   
/**
     * Class constructor
     *
     * @param dcCore   $core   dotclear core
     *
     * @access public
     */
   
public function __construct($core)
    {
       
$this->core       = $core;
       
$this->fav_defs   = new ArrayObject();
       
$this->ws         = $core->auth->user_prefs->addWorkspace('dashboard');
       
$this->user_prefs = [];

        if (
$this->ws->prefExists('favorites')) {
           
$this->local_prefs  = $this->ws->getLocal('favorites');
           
$this->global_prefs = $this->ws->getGlobal('favorites');
           
// Since we never know what user puts through user:preferences ...
           
if (!is_array($this->local_prefs)) {
               
$this->local_prefs = [];
            }
            if (!
is_array($this->global_prefs)) {
               
$this->global_prefs = [];
            }
        } else {
           
// No favorite defined ? Huhu, let's go for a migration
           
$this->migrateFavorites();
        }
    }

   
/**
     * setup - sets up favorites, fetch user favorites (against his permissions)
     *            This method is to be called after loading plugins
     *
     * @access public
     */
   
public function setup()
    {
       
defaultFavorites::initDefaultFavorites($this->core, $this);
       
$this->legacyFavorites();
       
$this->core->callBehavior('adminDashboardFavorites', $this->core, $this);
       
$this->setUserPrefs();
    }

   
/**
     * getFavorite - retrieves a favorite (complete description) from its id.
     *
     * @param mixed  $p   the favorite id, or an array having 1 key 'name' set to id, ther keys are merged to favorite.
     *
     * @access public
     *
     * @return mixed    array the favorite, false if not found (or not permitted)
     */
   
public function getFavorite($p)
    {
        if (
is_array($p)) {
           
$fname = $p['name'];
            if (!isset(
$this->fav_defs[$fname])) {
                return
false;
            }
           
$fattr = $p;
            unset(
$fattr['name']);
           
$fattr = array_merge($this->fav_defs[$fname], $fattr);
        } else {
            if (!isset(
$this->fav_defs[$p])) {
                return
false;
            }
           
$fattr = $this->fav_defs[$p];
        }
       
$fattr = array_merge(['id' => null, 'class' => null], $fattr);
        if (isset(
$fattr['permissions'])) {
            if (
is_bool($fattr['permissions']) && !$fattr['permissions']) {
                return
false;
            }
            if (!
$this->core->auth->check($fattr['permissions'], $this->core->blog->id)) {
                return
false;
            }
        } elseif (!
$this->core->auth->isSuperAdmin()) {
            return
false;
        }

        return
$fattr;
    }

   
/**
     * getFavorites - retrieves a list of favorites.
     *
     * @param array  $ids   an array of ids, as defined in getFavorite.
     *
     * @access public
     *
     * @return array array of favorites, can be empty if ids are not found (or not permitted)
     */
   
public function getFavorites($ids)
    {
       
$prefs = [];
        foreach (
$ids as $id) {
           
$f = $this->getFavorite($id);
            if (
$f !== false) {
               
$prefs[$id] = $f;
            }
        }

        return
$prefs;
    }

   
/**
     * setUserPrefs - get user favorites from settings. These are complete favorites, not ids only
     *                 returned favorites are the first non-empty list from :
     *                 * user-defined favorites
     *                 * globally-defined favorites
     *                 * a failback list "new post" (shall never be empty)
     *                This method is called by ::setup()
     *
     * @access protected
     */
   
protected function setUserPrefs()
    {
       
$this->user_prefs = $this->getFavorites($this->local_prefs);
        if (!
count($this->user_prefs)) {
           
$this->user_prefs = $this->getFavorites($this->global_prefs);
        }
        if (!
count($this->user_prefs)) {
           
$this->user_prefs = $this->getFavorites(['new_post']);
        }
       
$uri = explode('?', $_SERVER['REQUEST_URI']);
       
// take only last part of the URI, all plugins work like that
       
$uri[0] = preg_replace('#(.*?)([^/]+)$#', '$2', $uri[0]);
       
// Loop over prefs to enable active favorites
       
foreach ($this->user_prefs as $k => &$v) {
           
// duplicate request URI on each loop as it takes previous pref value ?!
           
$u = $uri;
            if (isset(
$v['active_cb']) && is_callable($v['active_cb'])) {
               
// Use callback if defined to match whether favorite is active or not
               
$v['active'] = call_user_func($v['active_cb'], $u[0], $_REQUEST);
            } else {
               
// Failback active detection. We test against URI name & parameters
               
$v['active'] = true; // true until something proves it is false
               
$u           = explode('?', $v['url'], 2);
                if (!
preg_match('/' . preg_quote($u[0], '/') . '/', $_SERVER['REQUEST_URI'])) {
                   
$v['active'] = false; // no URI match
               
}
                if (
count($u) == 2) {
                   
parse_str($u[1], $p);
                   
// test against each request parameter.
                   
foreach ($p as $k2 => $v2) {
                        if (!isset(
$_REQUEST[$k2]) || $_REQUEST[$k2] !== $v2) {
                           
$v['active'] = false;
                        }
                    }
                }
            }
        }
    }

   
/**
     * migrateFavorites - migrate dc < 2.6 favorites to new format
     *
     * @access protected
     */
   
protected function migrateFavorites()
    {
       
$fav_ws             = $this->core->auth->user_prefs->addWorkspace('favorites');
       
$this->local_prefs  = [];
       
$this->global_prefs = [];
        foreach (
$fav_ws->dumpPrefs() as $k => $v) {
           
$fav = @unserialize($v['value']);
            if (
is_array($fav)) {
                if (
$v['global']) {
                   
$this->global_prefs[] = $fav['name'];
                } else {
                   
$this->local_prefs[] = $fav['name'];
                }
            }
        }
       
$this->ws->put('favorites', $this->global_prefs, 'array', 'User favorites', true, true);
       
$this->ws->put('favorites', $this->local_prefs);
       
$this->user_prefs = $this->getFavorites($this->local_prefs);
    }

   
/**
     * legacyFavorites - handle legacy favorites using adminDashboardFavs behavior
     *
     * @access protected
     */
   
protected function legacyFavorites()
    {
       
$f = new ArrayObject();
       
$this->core->callBehavior('adminDashboardFavs', $this->core, $f);
        foreach (
$f as $k => $v) {
           
$fav = [
               
'title'       => __($v[1]),
               
'url'         => $v[2],
               
'small-icon'  => $v[3],
               
'large-icon'  => $v[4],
               
'permissions' => $v[5],
               
'id'          => $v[6],
               
'class'       => $v[7],
            ];
           
$this->register($v[0], $fav);
        }
    }

   
/**
     * getUserFavorites - returns favorites that correspond to current user
     *   (may be local, global, or failback favorites)
     *
     * @access public
     *
     * @return array array of favorites (enriched)
     */
   
public function getUserFavorites()
    {
        return
$this->user_prefs;
    }

   
/**
     * getFavoriteIDs - returns user-defined or global favorites ids list
     *                    shall not be called outside preferences.php...
     *
     * @param boolean  $global   if true, retrieve global favs, user favs otherwise
     *
     * @access public
     *
     * @return array array of favorites ids (only ids, not enriched)
     */
   
public function getFavoriteIDs($global = false)
    {
        return
$global ? $this->global_prefs : $this->local_prefs;
    }

   
/**
     * setFavoriteIDs - stores user-defined or global favorites ids list
     *                    shall not be called outside preferences.php...
     *
     * @param array  $ids   list of fav ids
     * @param boolean  $global   if true, retrieve global favs, user favs otherwise
     *
     * @access public
     */
   
public function setFavoriteIDs($ids, $global = false)
    {
       
$this->ws->put('favorites', $ids, 'array', null, true, $global);
    }

   
/**
     * getAvailableFavoritesIDs - returns all available fav ids
     *
     * @access public
     *
     * @return array array of favorites ids (only ids, not enriched)
     */
   
public function getAvailableFavoritesIDs()
    {
        return
array_keys($this->fav_defs->getArrayCopy()); // @phpstan-ignore-line
   
}

   
/**
     * appendMenuTitle - adds favorites section title to sidebar menu
     *                    shall not be called outside admin/prepend.php...
     *
     * @param array|ArrayObject  $menu   admin menu
     *
     * @access public
     */
   
public function appendMenuTitle($menu)
    {
       
$menu['Favorites']        = new dcMenu('favorites-menu', 'My favorites');
       
$menu['Favorites']->title = __('My favorites');
    }

   
/**
     * appendMenu - adds favorites items title to sidebar menu
     *                    shall not be called outside admin/prepend.php...
     *
     * @param array|ArrayObject  $menu   admin menu
     *
     * @access public
     */
   
public function appendMenu($menu)
    {
        foreach (
$this->user_prefs as $k => $v) {
           
$menu['Favorites']->addItem(
               
$v['title'],
               
$v['url'],
               
$v['small-icon'],
               
$v['active'],
               
true,
               
$v['id'],
               
$v['class'],
               
true
           
);
        }
    }

   
/**
     * appendDashboardIcons - adds favorites icons to index page
     *                    shall not be called outside admin/index.php...
     *
     * @param array  $icons   dashboard icon list to enrich
     *
     * @access public
     */
   
public function appendDashboardIcons($icons)
    {
        foreach (
$this->user_prefs as $k => $v) {
            if (isset(
$v['dashboard_cb']) && is_callable($v['dashboard_cb'])) {
               
$v = new ArrayObject($v);
               
call_user_func($v['dashboard_cb'], $this->core, $v);
            }
           
$icons[$k] = new ArrayObject([$v['title'], $v['url'], $v['large-icon']]);
           
$this->core->callBehavior('adminDashboardFavsIcon', $this->core, $k, $icons[$k]);
        }
    }

   
/**
     * register - registers a new favorite definition
     *
     * @param string  $id   favorite id
     * @param array  $data favorite information. Array keys are :
     *    'title' => favorite title (localized)
     *    'url' => favorite URL,
     *    'small-icon' => favorite small icon(s) (for menu)
     *    'large-icon' => favorite large icon(s) (for dashboard)
     *    'permissions' => (optional) comma-separated list of permissions for thie fav, if not set : no restriction
     *    'dashboard_cb' => (optional) callback to modify title if dynamic, if not set : title is taken as is
     *    'active_cb' => (optional) callback to tell whether current page matches favorite or not, for complex pages
     *
     * @access public
     *
     * @return dcFavorites instance
     */
   
public function register($id, $data)
    {
       
$this->fav_defs[$id] = $data;

        return
$this;
    }

   
/**
     * registerMultiple - registers a list of favorites definition
     *
     * @param array $data an array defining all favorites key is the id, value is the data.
     *                see register method for data format
     * @access public
     *
     * @return dcFavorites instance
     */
   
public function registerMultiple($data)
    {
        foreach (
$data as $k => $v) {
           
$this->register($k, $v);
        }

        return
$this;
    }

   
/**
     * exists - tells whether a fav definition exists or not
     *
     * @param string $id : the fav id to test
     *
     * @access public
     *
     * @return bool true if the fav definition exists, false otherwise
     */
   
public function exists($id)
    {
        return isset(
$this->fav_defs[$id]);
    }
}

/**
 * defaultFavorites -- default favorites definition
 */
class defaultFavorites
{
   
/**
     * Initializes the default favorites.
     *
     * @param      dcFavorites  $favs   The favs
     */
   
public static function initDefaultFavorites($core, $favs)
    {
       
$favs->registerMultiple([
           
'prefs' => [
               
'title'      => __('My preferences'),
               
'url'        => $core->adminurl->get('admin.user.preferences'),
               
'small-icon' => 'images/menu/user-pref.svg',
               
'large-icon' => 'images/menu/user-pref.svg', ],
           
'new_post' => [
               
'title'       => __('New post'),
               
'url'         => $core->adminurl->get('admin.post'),
               
'small-icon'  => ['images/menu/edit.svg', 'images/menu/edit-dark.svg'],
               
'large-icon'  => ['images/menu/edit.svg', 'images/menu/edit-dark.svg'],
               
'permissions' => 'usage,contentadmin',
               
'active_cb'   => ['defaultFavorites', 'newpostActive'], ],
           
'posts' => [
               
'title'        => __('Posts'),
               
'url'          => $core->adminurl->get('admin.posts'),
               
'small-icon'   => ['images/menu/entries.svg', 'images/menu/entries-dark.svg'],
               
'large-icon'   => ['images/menu/entries.svg', 'images/menu/entries-dark.svg'],
               
'permissions'  => 'usage,contentadmin',
               
'dashboard_cb' => ['defaultFavorites', 'postsDashboard'], ],
           
'comments' => [
               
'title'        => __('Comments'),
               
'url'          => $core->adminurl->get('admin.comments'),
               
'small-icon'   => ['images/menu/comments.svg', 'images/menu/comments-dark.svg'],
               
'large-icon'   => ['images/menu/comments.svg', 'images/menu/comments-dark.svg'],
               
'permissions'  => 'usage,contentadmin',
               
'dashboard_cb' => ['defaultFavorites', 'commentsDashboard'], ],
           
'search' => [
               
'title'       => __('Search'),
               
'url'         => $core->adminurl->get('admin.search'),
               
'small-icon'  => ['images/menu/search.svg','images/menu/search-dark.svg'],
               
'large-icon'  => ['images/menu/search.svg','images/menu/search-dark.svg'],
               
'permissions' => 'usage,contentadmin', ],
           
'categories' => [
               
'title'       => __('Categories'),
               
'url'         => $core->adminurl->get('admin.categories'),
               
'small-icon'  => ['images/menu/categories.svg', 'images/menu/categories-dark.svg'],
               
'large-icon'  => ['images/menu/categories.svg', 'images/menu/categories-dark.svg'],
               
'permissions' => 'categories', ],
           
'media' => [
               
'title'       => __('Media manager'),
               
'url'         => $core->adminurl->get('admin.media'),
               
'small-icon'  => ['images/menu/media.svg', 'images/menu/media-dark.svg'],
               
'large-icon'  => ['images/menu/media.svg', 'images/menu/media-dark.svg'],
               
'permissions' => 'media,media_admin', ],
           
'blog_pref' => [
               
'title'       => __('Blog settings'),
               
'url'         => $core->adminurl->get('admin.blog.pref'),
               
'small-icon'  => ['images/menu/blog-pref.svg','images/menu/blog-pref-dark.svg'],
               
'large-icon'  => ['images/menu/blog-pref.svg','images/menu/blog-pref-dark.svg'],
               
'permissions' => 'admin', ],
           
'blog_theme' => [
               
'title'       => __('Blog appearance'),
               
'url'         => $core->adminurl->get('admin.blog.theme'),
               
'small-icon'  => ['images/menu/themes.svg', 'images/menu/themes-dark.svg'],
               
'large-icon'  => ['images/menu/themes.svg', 'images/menu/themes-dark.svg'],
               
'permissions' => 'admin', ],
           
'blogs' => [
               
'title'       => __('Blogs'),
               
'url'         => $core->adminurl->get('admin.blogs'),
               
'small-icon'  => ['images/menu/blogs.svg', 'images/menu/blogs-dark.svg'],
               
'large-icon'  => ['images/menu/blogs.svg', 'images/menu/blogs-dark.svg'],
               
'permissions' => 'usage,contentadmin', ],
           
'users' => [
               
'title'      => __('Users'),
               
'url'        => $core->adminurl->get('admin.users'),
               
'small-icon' => 'images/menu/users.svg',
               
'large-icon' => 'images/menu/users.svg', ],
           
'plugins' => [
               
'title'      => __('Plugins management'),
               
'url'        => $core->adminurl->get('admin.plugins'),
               
'small-icon' => ['images/menu/plugins.svg', 'images/menu/plugins-dark.svg'],
               
'large-icon' => ['images/menu/plugins.svg', 'images/menu/plugins-dark.svg'], ],
           
'langs' => [
               
'title'      => __('Languages'),
               
'url'        => $core->adminurl->get('admin.langs'),
               
'small-icon' => ['images/menu/langs.svg', 'images/menu/langs-dark.svg'],
               
'large-icon' => ['images/menu/langs.svg', 'images/menu/langs-dark.svg'], ],
           
'help' => [
               
'title'      => __('Global help'),
               
'url'        => $core->adminurl->get('admin.help'),
               
'small-icon' => 'images/menu/help.svg',
               
'large-icon' => 'images/menu/help.svg', ],
        ]);
    }

   
/**
     * Helper for posts icon on dashboard
     *
     * @param      dcCore  $core   The core
     * @param      mixed   $v      { parameter_description }
     */
   
public static function postsDashboard($core, $v)
    {
       
$post_count  = $core->blog->getPosts([], true)->f(0);
       
$str_entries = __('%d post', '%d posts', $post_count);
       
$v['title']  = sprintf($str_entries, $post_count);
    }

   
/**
     * Helper for new post active menu
     *
     * Take account of post edition (if id is set)
     *
     * @param  string   $request_uri    The URI
     * @param  array    $request_params The params
     * @return boolean                  Active
     */
   
public static function newpostActive($request_uri, $request_params)
    {
        return
'post.php' == $request_uri && !isset($request_params['id']);
    }

   
/**
     * Helper for comments icon on dashboard
     *
     * @param      dcCore  $core   The core
     * @param      mixed   $v      { parameter_description }
     */
   
public static function commentsDashboard($core, $v)
    {
       
$comment_count = $core->blog->getComments([], true)->f(0);
       
$str_comments  = __('%d comment', '%d comments', $comment_count);
       
$v['title']    = sprintf($str_comments, $comment_count);
    }
}