From f2e8775454f2d1ed00087361755bda9ad3b2016f Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Sun, 16 Apr 2023 02:48:32 +0200 Subject: [PATCH] use namespace --- _config.php | 75 --- _install.php | 47 -- css/backend.css | 8 + inc/class.advanced.cleaner.php | 183 ------ inc/class.dc.advanced.cleaner.php | 75 --- inc/class.dc.uninstaller.php | 356 ------------ inc/lib.advanced.cleaner.php | 519 ------------------ ...lib.dc.advanced.cleaner.activityreport.php | 43 -- js/backend.js | 2 +- src/Backend.php | 263 ++------- src/Manage.php | 283 ++++++---- src/ManageVars.php | 72 +++ src/My.php | 58 ++ src/Prepend.php | 80 +-- style.css | 10 - 15 files changed, 407 insertions(+), 1667 deletions(-) delete mode 100644 _config.php delete mode 100644 _install.php create mode 100644 css/backend.css delete mode 100644 inc/class.advanced.cleaner.php delete mode 100644 inc/class.dc.advanced.cleaner.php delete mode 100644 inc/class.dc.uninstaller.php delete mode 100644 inc/lib.advanced.cleaner.php delete mode 100644 inc/lib.dc.advanced.cleaner.activityreport.php create mode 100644 src/ManageVars.php create mode 100644 src/My.php delete mode 100644 style.css diff --git a/_config.php b/_config.php deleted file mode 100644 index 6be05da..0000000 --- a/_config.php +++ /dev/null @@ -1,75 +0,0 @@ -auth->isSuperAdmin()) { - return null; -} - -if (!empty($_POST['save'])) { - try { - dcCore::app()->blog->settings->__get(basename(__DIR__))->dropEvery( - 'dcAdvancedCleaner_behavior_active' - ); - dcCore::app()->blog->settings->__get(basename(__DIR__))->put( - 'dcAdvancedCleaner_behavior_active', - !empty($_POST['behavior_active']), - 'boolean', - null, - true, - true - ); - dcCore::app()->blog->settings->__get(basename(__DIR__))->dropEvery( - 'dcAdvancedCleaner_dcproperty_hide' - ); - dcCore::app()->blog->settings->__get(basename(__DIR__))->put( - 'dcAdvancedCleaner_dcproperty_hide', - !empty($_POST['dcproperty_hide']), - 'boolean', - null, - true, - true - ); - dcAdminNotices::addSuccessNotice( - __('Configuration successfully updated.') - ); - dcCore::app()->adminurl->redirect( - 'admin.plugins', - [ - 'module' => basename(__DIR__), - 'conf' => 1, - 'redir' => empty($_REQUEST['redir']) ? dcCore::app()->admin->list->getURL() . '#plugins' : $_REQUEST['redir'], - ] - ); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} -echo ' -

-

' . __('Enable actions set in _uninstall.php files.') . '

-

-

' . -__('Prevent from deleting Dotclear important properties.') . '

'; diff --git a/_install.php b/_install.php deleted file mode 100644 index 3f7997e..0000000 --- a/_install.php +++ /dev/null @@ -1,47 +0,0 @@ -newVersion( - basename(__DIR__), - dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') - )) { - return null; - } - - dcCore::app()->blog->settings->get(basename(__DIR__))->put( - 'dcAdvancedCleaner_behavior_active', - true, - 'boolean', - '', - false, - true - ); - dcCore::app()->blog->settings->get(basename(__DIR__))->put( - 'dcAdvancedCleaner_dcproperty_hide', - true, - 'boolean', - '', - false, - true - ); - - return true; -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - - return false; -} diff --git a/css/backend.css b/css/backend.css new file mode 100644 index 0000000..84eaeb8 --- /dev/null +++ b/css/backend.css @@ -0,0 +1,8 @@ +.offline label{ + font-weight:bold; + color:#c44d58; +} +.module-distrib img { + with: 16px; + height: 16px; +} \ No newline at end of file diff --git a/inc/class.advanced.cleaner.php b/inc/class.advanced.cleaner.php deleted file mode 100644 index 33dc248..0000000 --- a/inc/class.advanced.cleaner.php +++ /dev/null @@ -1,183 +0,0 @@ - '', - 'name' => '', - 'desc' => '', - ]; - - private $actions = []; - - final public function __construct() - { - $this->init(); - } - - public static function create(arrayObject $o) - { - $c = get_called_class(); - $o->append(new $c()); - } - - final public function __get(string $property) - { - return $this->getProperty($property); - } - - final public function getProperty(string $property) - { - return $this->properties[$property] ?? null; - } - - final protected function setProperties($property, $value = null): bool - { - $properties = is_array($property) ? $property : [$property => $value]; - foreach ($properties as $k => $v) { - if (isset($this->properties[$k])) { - $this->properties[$k] = (string) $v; - } - } - - return true; - } - - final public function getActions() - { - return $this->actions; - } - - final protected function setActions($action, $name = null): bool - { - $actions = is_array($action) ? $action : [$action => $name]; - foreach ($actions as $k => $v) { - $this->actions[$k] = (string) $v; - } - - return true; - } - - abstract protected function init(): bool; - - abstract public function error($action): string; - - abstract public function official(): array; - - abstract public function get(): array; - - abstract public function set($action, $ns): bool; - - # helpers - - protected static function getDirs($roots) - { - if (!is_array($roots)) { - $roots = [$roots]; - } - $rs = []; - $i = 0; - foreach ($roots as $root) { - $dirs = files::scanDir($root); - foreach ($dirs as $k) { - if ('.' == $k || '..' == $k || !is_dir($root . '/' . $k)) { - continue; - } - $rs[$i]['key'] = $k; - $rs[$i]['value'] = count(self::scanDir($root . '/' . $k)); - $i++; - } - } - - return $rs; - } - - protected static function delDir($roots, $folder, $delfolder = true) - { - if (strpos($folder, '/')) { - return false; - } - if (!is_array($roots)) { - $roots = [$roots]; - } - foreach ($roots as $root) { - if (file_exists($root . '/' . $folder)) { - return self::delTree($root . '/' . $folder, $delfolder); - } - } - - return false; - } - - protected static function scanDir($path, $dir = '', $res = []) - { - $exclude = self::$exclude; - - $path = path::real($path); - if (!is_dir($path) || !is_readable($path)) { - return []; - } - $files = files::scandir($path); - - foreach ($files as $file) { - if (in_array($file, $exclude)) { - continue; - } - if (is_dir($path . '/' . $file)) { - $res[] = $file; - $res = self::scanDir($path . '/' . $file, $dir . '/' . $file, $res); - } else { - $res[] = empty($dir) ? $file : $dir . '/' . $file; - } - } - - return $res; - } - - protected static function delTree($dir, $delroot = true) - { - if (!is_dir($dir) || !is_readable($dir)) { - return false; - } - if (substr($dir, -1) != '/') { - $dir .= '/'; - } - if (($d = @dir($dir)) === false) { - return false; - } - while (($entryname = $d->read()) !== false) { - if ($entryname != '.' && $entryname != '..') { - if (is_dir($dir . '/' . $entryname)) { - if (!self::delTree($dir . '/' . $entryname)) { - return false; - } - } else { - if (!@unlink($dir . '/' . $entryname)) { - return false; - } - } - } - } - $d->close(); - - if ($delroot) { - return @rmdir($dir); - } - - return true; - } -} diff --git a/inc/class.dc.advanced.cleaner.php b/inc/class.dc.advanced.cleaner.php deleted file mode 100644 index fc10927..0000000 --- a/inc/class.dc.advanced.cleaner.php +++ /dev/null @@ -1,75 +0,0 @@ -callBehavior('advancedCleanerAdd', $cleaners); - - foreach ($cleaners as $cleaner) { - if ($cleaner instanceof advancedCleaner && !isset($this->cleaners[$cleaner->id])) { - $this->cleaners[$cleaner->id] = $cleaner; - } - } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } - } - - public function get($type = null, $silent = false) - { - if (null === $type) { - return $this->cleaners; - } - if (isset($this->cleaners[$type])) { - return $this->cleaners[$type]; - } - if ($silent) { - return false; - } - - throw new exception(sprintf(__('unknow cleaner type %s'), $type)); - } - - public function set($type, $action, $ns) - { - if (!isset($this->cleaners[$type])) { - throw new exception(sprintf(__('unknow cleaner type %s'), $type)); - } - if ($ns == basename(dirname('../' . __DIR__))) { - throw new exception(__("dcAdvancedCleaner can't remove itself")); - } - - # BEHAVIOR dcAdvancedCleanerBeforeAction - dcCore::app()->callBehavior('dcAdvancedCleanerBeforeAction', $type, $action, $ns); - - $ret = $this->cleaners[$type]->set($action, $ns); - - if ($ret === false) { - $msg = $this->cleaners[$type]->error($action); - - throw new Exception($msg ?? __('Unknow error')); - } - - return true; - } -} diff --git a/inc/class.dc.uninstaller.php b/inc/class.dc.uninstaller.php deleted file mode 100644 index 20de787..0000000 --- a/inc/class.dc.uninstaller.php +++ /dev/null @@ -1,356 +0,0 @@ - [], 'callback' => []]; - protected $callbacks = ['user' => [], 'callback' => []]; - - protected $id = null; - protected $mroot = null; - - private $ac; - private $allowed_actions = null; - - /** - * Object constructor. - */ - public function __construct() - { - $this->ac = new dcAdvancedCleaner(); - - $res = []; - foreach ($this->ac->get() as $cleaner) { - $res[$cleaner->id] = $cleaner->getActions(); - } - $this->allowed_actions = $res; - } - - public function getAllowedActions() - { - return $this->allowed_actions; - } - - /** - * Loads modules. - * - * Files _defines.php and _uninstall.php must be present on module - * to be recognized. - * (path separator depends on your OS). - * - * @param string $path Separated list of paths - */ - public function loadModules($path) - { - $this->path = explode(PATH_SEPARATOR, $path); - - foreach ($this->path as $root) { - if (!is_dir($root) || !is_readable($root)) { - continue; - } - if (substr($root, -1) != '/') { - $root .= '/'; - } - if (($d = @dir($root)) === false) { - continue; - } - while (($entry = $d->read()) !== false) { - $full_entry = $root . '/' . $entry; - - if ($entry != '.' && $entry != '..' && is_dir($full_entry)) { - $this->loadModule($full_entry); - } - } - $d->close(); - } - - # Sort modules by name - uasort($this->modules, [$this, 'sortModules']); - } - - /** - * Load one module. - * - * Files _defines.php and _uninstall.php must be present on module - * to be recognized. - * - * @param string $root path of module - */ - public function loadModule($root) - { - if (file_exists($root . '/_define.php') - && file_exists($root . '/_uninstall.php')) { - $this->id = basename($root); - $this->mroot = $root; - - require $root . '/_define.php'; - require $root . '/_uninstall.php'; - - $this->id = null; - $this->mroot = null; - } - } - - /** - * This method registers a module in modules list. - * - * @param string $name Module name - * @param string $desc Module description - * @param string $author Module author name - * @param string $version Module version - */ - public function registerModule($name, $desc, $author, $version, $properties = []) - { - if ($this->id) { - $this->modules[$this->id] = [ - 'root' => $this->mroot, - 'name' => $name, - 'desc' => $desc, - 'author' => $author, - 'version' => $version, - 'root_writable' => is_writable($this->mroot), - ]; - } - } - - /** - * Returns all modules associative array or only one module if $id - * is present. - * - * @param string $id Optionnal module ID - * - * @return array Modules - */ - public function getModules($id = null) - { - if ($id && isset($this->modules[$id])) { - return $this->modules[$id]; - } - - return $this->modules; - } - - /** - * Returns true if the module with ID $id exists. - * - * @param string $id Module ID - * - * @return boolean Success - */ - public function moduleExists($id) - { - return isset($this->modules[$id]); - } - - /** - * Add a predefined action to unsintall features. - * - * This action is set in _uninstall.php. - * - * @param string $type Type of action (from $allowed_actions) - * @param string $action Action (from $allowed_actions) - * @param string $ns Name of setting related to module. - * @param string $desc Description of action - */ - public function addUserAction($type, $action, $ns, $desc = '') - { - $this->addAction('user', $type, $action, $ns, $desc); - } - - public function addDirectAction($type, $action, $ns, $desc = '') - { - $this->addAction('direct', $type, $action, $ns, $desc); - } - - private function addAction($group, $type, $action, $ns, $desc) - { - $group = self::group($group); - - if (null === $this->id) { - return null; - } - if (empty($type) || empty($ns)) { - return null; - } - if (!isset($this->allowed_actions[$type][$action])) { - return null; - } - if (empty($desc)) { - $desc = __($action); - } - $this->actions[$group][$this->id][$type][] = [ - 'ns' => $ns, - 'action' => $action, - 'desc' => $desc, - ]; - } - - /** - * Returns modules $id predefined actions associative array - * - * @param string $id Optionnal module ID - * @return array Modules id - */ - public function getUserActions($id) - { - return $this->getActions('user', $id); - } - - public function getDirectActions($id) - { - return $this->getActions('direct', $id); - } - - protected function getActions($group, $id) - { - $group = self::group($group); - - if (!isset($this->actions[$group][$id])) { - return []; - } - $res = []; - foreach ($this->allowed_actions as $k => $v) { - if (!isset($this->actions[$group][$id][$k])) { - continue; - } - $res[$k] = $this->actions[$group][$id][$k]; - } - - return $res; - } - - /** - * Add a callable function for unsintall features. - * - * This action is set in _uninstall.php. - * - * @param string $func Callable function - * @param string $desc Description of action - */ - protected function addUserCallback($func, $desc = '') - { - $this->addCallback('user', $func, $desc); - } - - protected function addDirectCallback($func, $desc = '') - { - $this->addCallback('direct', $func, $desc); - } - - private function addCallback($group, $func, $desc) - { - $group = self::group($group); - - if (null === $this->id) { - return null; - } - if (empty($desc)) { - $desc = __('extra action'); - } - if (!is_callable($func)) { - return null; - } - $this->callbacks[$group][$this->id][] = [ - 'func' => $func, - 'desc' => $desc, - ]; - } - - /** - * Returns modules $id callback actions associative array - - * @param string $id Optionnal module ID - * - * @return array Modules id - */ - public function getUserCallbacks($id) - { - return $this->getCallbacks('user', $id); - } - - public function getDirectCallbacks($id) - { - return $this->getCallbacks('direct', $id); - } - - protected function getCallbacks($group, $id) - { - $group = self::group($group); - - if (!isset($this->callbacks[$group][$id])) { - return []; - } - - return $this->callbacks[$group][$id]; - } - - /** - * Execute a predifined action. - * - * This function call dcAdvancedCleaner to do actions. - * - * @param string $type Type of action (from $allowed_actions) - * @param string $action Action (from $allowed_actions) - * @param string $ns Name of setting related to module. - * - * @return boolean Success - */ - public function execute($type, $action, $ns) - { - if (!isset($this->allowed_actions[$type][$action]) || empty($ns)) { - return false; - } - $this->ac->set($type, $action, $ns); - - return true; - } - - private function sortModules($a, $b) - { - return strcasecmp($a['name'], $b['name']); - } - - private function group($group) - { - return in_array($group, ['user','direct']) ? $group : null; - } -} diff --git a/inc/lib.advanced.cleaner.php b/inc/lib.advanced.cleaner.php deleted file mode 100644 index 371175d..0000000 --- a/inc/lib.advanced.cleaner.php +++ /dev/null @@ -1,519 +0,0 @@ -setProperties([ - 'id' => 'settings', - 'name' => __('Settings'), - 'desc' => __('Namespaces registered in dcSettings'), - ]); - - $this->setActions([ - 'delete_global' => __('delete global settings'), - 'delete_local' => __('delete blog settings'), - 'delete_all' => __('delete all settings'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'delete_global') { - return __('Failed to delete global settings'); - } - if ($action == 'delete_local') { - return __('Failed to delete local settings'); - } - if ($action == 'delete_all') { - return __('Failed to delete all settings'); - } - - return ''; - } - - public function official(): array - { - return [ - 'akismet', - 'antispam', - 'breadcrumb', - 'dcckeditor', - 'dclegacyeditor', - 'maintenance', - 'pages', - 'pings', - 'system', - 'themes', - 'widgets', - ]; - } - - public function get(): array - { - $res = dcCore::app()->con->select( - 'SELECT setting_ns ' . - 'FROM ' . dcCore::app()->prefix . 'setting ' . - 'WHERE blog_id IS NULL ' . - 'OR blog_id IS NOT NULL ' . - 'GROUP BY setting_ns' - ); - - $rs = []; - $i = 0; - while ($res->fetch()) { - $rs[$i]['key'] = $res->setting_ns; - $rs[$i]['value'] = dcCore::app()->con->select( - 'SELECT count(*) FROM ' . dcCore::app()->prefix . 'setting ' . - "WHERE setting_ns = '" . $res->setting_ns . "' " . - 'AND (blog_id IS NULL OR blog_id IS NOT NULL) ' . - 'GROUP BY setting_ns ' - )->f(0); - $i++; - } - - return $rs; - } - - public function set($action, $ns): bool - { - if ($action == 'delete_global') { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . 'setting ' . - 'WHERE blog_id IS NULL ' . - "AND setting_ns = '" . dcCore::app()->con->escapeStr((string) $ns) . "' " - ); - - return true; - } - if ($action == 'delete_local') { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . 'setting ' . - "WHERE blog_id = '" . dcCore::app()->con->escapeStr((string) dcCore::app()->blog->id) . "' " . - "AND setting_ns = '" . dcCore::app()->con->escapeStr((string) $ns) . "' " - ); - - return true; - } - if ($action == 'delete_all') { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . 'setting ' . - "WHERE setting_ns = '" . dcCore::app()->con->escapeStr((string) $ns) . "' " . - "AND (blog_id IS NULL OR blog_id != '') " - ); - - return true; - } - - return false; - } -} - -class advancedCleanerTables extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'tables', - 'name' => __('Tables'), - 'desc' => __('All database tables of Dotclear'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - 'empty' => __('empty'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'empty') { - return __('Failed to empty table'); - } - if ($action == 'delete') { - return __('Failed to delete table'); - } - - return ''; - } - - public function official(): array - { - return [ - 'blog', - 'category', - 'comment', - 'link', - 'log', - 'media', - 'meta', - 'permissions', - 'ping', - 'post', - 'post_media', - 'pref', - 'session', - 'setting', - 'spamrule', - 'user', - 'version', - ]; - } - - public function get(): array - { - $object = dbSchema::init(dcCore::app()->con); - $res = $object->getTables(); - - $rs = []; - $i = 0; - foreach ($res as $k => $v) { - if ('' != dcCore::app()->prefix) { - if (!preg_match('/^' . preg_quote(dcCore::app()->prefix) . '(.*?)$/', $v, $m)) { - continue; - } - $v = $m[1]; - } - $rs[$i]['key'] = $v; - $rs[$i]['value'] = dcCore::app()->con->select('SELECT count(*) FROM ' . $res[$k])->f(0); - $i++; - } - - return $rs; - } - - public function set($action, $ns): bool - { - if (in_array($action, ['empty', 'delete'])) { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->con->escapeSystem(dcCore::app()->prefix . $ns) - ); - } - if ($action == 'empty') { - return true; - } - if ($action == 'delete') { - dcCore::app()->con->execute( - 'DROP TABLE ' . dcCore::app()->con->escapeSystem(dcCore::app()->prefix . $ns) - ); - - return true; - } - - return false; - } -} - -class advancedCleanerVersions extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'versions', - 'name' => __('Versions'), - 'desc' => __('Versions registered in table "version" of Dotclear'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'delete') { - return __('Failed to delete version'); - } - - return ''; - } - - public function official(): array - { - return [ - 'antispam', - 'blogroll', - 'blowupConfig', - 'core', - 'dcCKEditor', - 'dcLegacyEditor', - 'pages', - 'pings', - 'simpleMenu', - 'tags', - 'widgets', - ]; - } - - public function get(): array - { - $res = dcCore::app()->con->select('SELECT * FROM ' . dcCore::app()->prefix . 'version'); - - $rs = []; - $i = 0; - while ($res->fetch()) { - $rs[$i]['key'] = $res->module; - $rs[$i]['value'] = $res->version; - $i++; - } - - return $rs; - } - - public function set($action, $ns): bool - { - if ($action == 'delete') { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . 'version ' . - "WHERE module = '" . dcCore::app()->con->escapeStr((string) $ns) . "' " - ); - - return true; - } - - return false; - } -} - -class advancedCleanerPlugins extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'plugins', - 'name' => __('Plugins'), - 'desc' => __('Folders from plugins directories'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - 'empty' => __('empty'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'empty') { - return __('Failed to empty plugin folder'); - } - if ($action == 'delete') { - return __('Failed to delete plugin folder'); - } - - return ''; - } - - public function official(): array - { - return explode(',', DC_DISTRIB_PLUGINS); - } - - public function get(): array - { - $res = self::getDirs(explode(PATH_SEPARATOR, DC_PLUGINS_ROOT)); - sort($res); - - return $res; - } - - public function set($action, $ns): bool - { - if ($action == 'empty') { - $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); - self::delDir($res, $ns, false); - - return true; - } - if ($action == 'delete') { - $res = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); - self::delDir($res, $ns, true); - - return true; - } - - return false; - } -} - -class advancedCleanerThemes extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'themes', - 'name' => __('Themes'), - 'desc' => __('Folders from blog themes directory'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - 'empty' => __('empty'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'empty') { - return __('Failed to empty themes folder'); - } - if ($action == 'delete') { - return __('Failed to delete themes folder'); - } - - return ''; - } - - public function official(): array - { - return explode(',', DC_DISTRIB_THEMES); - } - - public function get(): array - { - $res = self::getDirs(dcCore::app()->blog->themes_path); - sort($res); - - return $res; - } - - public function set($action, $ns): bool - { - if ($action == 'empty') { - self::delDir(dcCore::app()->blog->themes_path, $ns, false); - - return true; - } - if ($action == 'delete') { - self::delDir(dcCore::app()->blog->themes_path, $ns, true); - - return true; - } - - return false; - } -} - -class advancedCleanerCaches extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'caches', - 'name' => __('Cache'), - 'desc' => __('Folders from cache directory'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - 'empty' => __('empty'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'empty') { - return __('Failed to empty cache folder'); - } - if ($action == 'delete') { - return __('Failed to delete cache folder'); - } - - return ''; - } - - public function official(): array - { - return ['cbfeed', 'cbtpl', 'dcrepo', 'versions']; - } - - public function get(): array - { - return self::getDirs(DC_TPL_CACHE); - } - - public function set($action, $ns): bool - { - if ($action == 'empty') { - self::delDir(DC_TPL_CACHE, $ns, false); - - return true; - } - if ($action == 'delete') { - self::delDir(DC_TPL_CACHE, $ns, true); - - return true; - } - - return false; - } -} - -class advancedCleanerVars extends advancedCleaner -{ - protected function init(): bool - { - $this->setProperties([ - 'id' => 'vars', - 'name' => __('Var'), - 'desc' => __('Folders from Dotclear VAR directory'), - ]); - - $this->setActions([ - 'delete' => __('delete'), - ]); - - return true; - } - - public function error($action): string - { - if ($action == 'delete') { - return __('Failed to delete var folder'); - } - - return ''; - } - - public function official(): array - { - return []; - } - - public function get(): array - { - return self::getDirs(DC_VAR); - } - - public function set($action, $ns): bool - { - if ($action == 'delete') { - self::delDir(DC_VAR, $ns, true); - - return true; - } - - return false; - } -} diff --git a/inc/lib.dc.advanced.cleaner.activityreport.php b/inc/lib.dc.advanced.cleaner.activityreport.php deleted file mode 100644 index c8eb46f..0000000 --- a/inc/lib.dc.advanced.cleaner.activityreport.php +++ /dev/null @@ -1,43 +0,0 @@ -activityReport->addLog('dcadvancedcleaner', 'maintenance', [$type,$action, $ns]); - } - - public static function add() - { - // This file is used with plugin activityReport - dcCore::app()->activityReport->addGroup( - 'dcadvancedcleaner', - __('Plugin dcAdvancedCleaner') - ); - - // from BEHAVIOR dcAdvancedCleanerBeforeAction - // in dcAdvancedCleaner/inc/class.dc.advanced.cleaner.php - dcCore::app()->activityReport->addAction( - 'dcadvancedcleaner', - 'maintenance', - __('Maintenance'), - __('New action from dcAdvancedCleaner has been made with type="%s", action="%s", ns="%s".'), - 'dcAdvancedCleanerBeforeAction', - ['dcAdvancedCleanerActivityReportBehaviors', 'maintenance'] - ); - } -} diff --git a/js/backend.js b/js/backend.js index f36deef..744a0cc 100644 --- a/js/backend.js +++ b/js/backend.js @@ -3,6 +3,6 @@ $(function () { $('#parts_menu input[type=submit]').hide(); - $('#parts_menu #part').on('change', function () {this.form.submit();}); + $('#parts_menu #select_part').on('change', function () {this.form.submit();}); dotclear.condSubmit('#form-funcs td input[type=checkbox]', '#form-funcs #do-action'); }); \ No newline at end of file diff --git a/src/Backend.php b/src/Backend.php index b9df92c..ccc3f5e 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -10,232 +10,55 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( - __('Advanced cleaner'), - dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), - dcPage::getPF(basename(__DIR__) . '/icon.svg'), - preg_match( - '/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__))) . '(&.*)?$/', - $_SERVER['REQUEST_URI'] - ), - dcCore::app()->auth->isSuperAdmin() -); +namespace Dotclear\Plugin\dcAdvancedCleaner; -dcCore::app()->addBehaviors([ - 'adminDashboardFavoritesV2' => function ($favs) { - $favs->register(basename(__DIR__), [ - 'title' => __('Advanced cleaner'), - 'url' => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), - 'small-icon' => dcPage::getPF(basename(__DIR__) . '/icon.svg'), - 'large-icon' => dcPage::getPF(basename(__DIR__) . '/icon-big.svg'), - //'permissions' => dcCore::app()->auth->isSuperAdmin(), - ]); - }, +use dcAdmin; +use dcCore; +use dcFavorites; +use dcNsProcess; +use dcPage; - 'pluginsToolsTabsV2' => function () { - if (!dcCore::app()->blog->settings->__get(basename(__DIR__))->dcAdvancedCleaner_behavior_active) { - return null; - } - - $path = DC_PLUGINS_ROOT; - $redir = dcCore::app()->adminurl->get('admin.plugins', [], '#uninstaller'); - $title = ''; - - $uninstaller = new dcUninstaller(); - $uninstaller->loadModules($path); - $modules = $uninstaller->getModules(); - $props = $uninstaller->getAllowedActions(); - - echo '

' . __('Advanced uninstall') . '

'; - - if (!count($modules)) { - echo '

' . __('There is no module with uninstall features') . '

'; - - return null; - } - - echo - '

' . __('List of modules with advanced uninstall features') . '

' . - '
' . - '' . - ''; - - foreach ($props as $pro_id => $prop) { - echo ''; - } - - echo '' . ''; - - $i = 0; - foreach ($modules as $module_id => $module) { - echo - '' . - '' . - ''; - - $actions = $uninstaller->getUserActions($module_id); - - foreach ($props as $prop_id => $prop) { - echo ''; - - continue; - } - - $j = 0; - foreach ($actions[$prop_id] as $action_id => $action) { - if (!isset($props[$prop_id][$action['action']])) { - continue; - } - $ret = base64_encode(serialize([ - 'type' => $prop_id, - 'action' => $action['action'], - 'ns' => $action['ns'], - ])); - - echo '
'; - - $j++; - } - echo ''; - } - - echo ''; - } - echo - '
' . __('module') . '' . __($pro_id) . '' . __('other') . '
' . $module_id . '' . $module['version'] . ''; - - if (!isset($actions[$prop_id])) { - echo '--'; - - $callbacks = $uninstaller->getUserCallbacks($module_id); - - if (empty($callbacks)) { - echo '--'; - } - - $k = 0; - foreach ($callbacks as $callback_id => $callback) { - $ret = base64_encode(serialize($callback['func'])); - - echo '
'; - } - - echo '
' . - '

' . - dcCore::app()->formNonce() . - form::hidden(['path'], $path) . - form::hidden(['redir'], $redir) . - form::hidden(['action'], 'uninstall') . - ' ' . - '

' . - '
'; - - echo ''; - }, - - 'adminModulesListDoActions' => function ($list, $modules, $type) { - if (!dcCore::app()->blog->settings->__get(basename(__DIR__))->dcAdvancedCleaner_behavior_active) { - return null; - } - - if (!isset($_POST['action']) || $_POST['action'] != 'uninstall' - || (empty($_POST['extras']) && empty($_POST['actions'])) - ) { - return null; - } - - $uninstaller = new dcUninstaller(); - $uninstaller->loadModules($_POST['path']); - $modules = $uninstaller->getModules(); - $props = $uninstaller->getAllowedActions(); - - try { - // Extras - if (!empty($_POST['extras'])) { - foreach ($_POST['extras'] as $module_id => $extras) { - foreach ($extras as $k => $sentence) { - $extra = @unserialize(@base64_decode($sentence)); - - if (!$extra || !is_callable($extra)) { - continue; - } - call_user_func($extra, $module_id); - } - } - } - // Actions - if (!empty($_POST['actions'])) { - foreach ($_POST['actions'] as $module_id => $actions) { - foreach ($actions as $k => $sentence) { - $action = @unserialize(@base64_decode($sentence)); - - if (!$action - || !isset($action['type']) - || !isset($action['action']) - || !isset($action['ns']) - ) { - continue; - } - $uninstaller->execute($action['type'], $action['action'], $action['ns']); - } - } - } - dcAdminNotices::addSuccessNotice(__('Action successfuly excecuted')); - http::redirect($_POST['redir']); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } - }, - - 'pluginsBeforeDelete' => function ($plugin) { - dcAdvancedCleanerModuleBeforeDelete($plugin); - }, - - 'themeBeforeDelete' => function ($theme) { - dcAdvancedCleanerModuleBeforeDelete($theme); - }, -]); - -function dcAdvancedCleanerModuleBeforeDelete($module) +class Backend extends dcNsProcess { - if (!dcCore::app()->blog->settings->__get(basename(__DIR__))->dcAdvancedCleaner_behavior_active) { - return null; + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && My::phpCompliant(); + + return static::$init; } - $done = false; - - $uninstaller = new dcUninstaller(); - $uninstaller->loadModule($module['root']); - - $m_callbacks = $uninstaller->getDirectCallbacks($module['id']); - $m_actions = $uninstaller->getDirectActions($module['id']); - - foreach ($m_callbacks as $k => $callback) { - if (!isset($callback['func']) || !is_callable($callback['func'])) { - continue; - } - call_user_func($callback['func'], $module); - $done = true; - } - foreach ($m_actions as $type => $actions) { - foreach ($actions as $v) { - $uninstaller->execute($type, $v['action'], $v['ns']); - $done = true; - } - } - if ($done) { - if ('theme' == $module['type']) { - dcCore::app()->adminurl->redirect('admin.blog.theme', ['del' => 1]); - } else { - dcCore::app()->adminurl->redirect('admin.plugins', ['removed' => 1]); + public static function process(): bool + { + if (!static::$init || !dcCore::app()->plugins->moduleExists('Uninstaller')) { + return false; } + + dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + My::name(), + dcCore::app()->adminurl?->get('admin.plugin.' . My::id()), + dcPage::getPF(My::id() . '/icon.svg'), + preg_match( + '/' . preg_quote(dcCore::app()->adminurl?->get('admin.plugin.' . My::id())) . '(&.*)?$/', + $_SERVER['REQUEST_URI'] + ), + dcCore::app()->auth?->isSuperAdmin() + ); + + dcCore::app()->addBehaviors([ + 'adminDashboardFavoritesV2' => function (dcFavorites $favs): void { + $favs->register(My::id(), [ + 'title' => My::name(), + 'url' => dcCore::app()->adminurl?->get('admin.plugin.' . My::id()), + 'small-icon' => dcPage::getPF(My::id() . '/icon.svg'), + 'large-icon' => dcPage::getPF(My::id() . '/icon-big.svg'), + //'permissions' => dcCore::app()->auth?->isSuperAdmin(), + ]); + }, + ]); + + return true; } } diff --git a/src/Manage.php b/src/Manage.php index 1cde6c8..7c18286 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -10,117 +10,196 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -dcPage::checkSuper(); +namespace Dotclear\Plugin\dcAdvancedCleaner; -$ac = new dcAdvancedCleaner(); +use dcCore; +use dcNsProcess; +use dcPage; +use Dotclear\Helper\Html\Form\{ + Checkbox, + Div, + Form, + Hidden, + Label, + Note, + Para, + Select, + Submit +}; +use Dotclear\Helper\Html\Html; +use Exception; -$cleaner = false; -$select_menu = []; -foreach ($ac->get() as $k) { - $select_menu[$k->name] = $k->id; - if ($k->id == $_REQUEST['part']) { - $cleaner = $k; +class Manage extends dcNsProcess +{ + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && dcCore::app()->auth?->isSuperAdmin() + && My::phpCompliant(); + + return static::$init; } -} -if (!$cleaner) { - if (!($cleaner = $ac->get('caches', true))) { - return false; - } -} -# Actions -if (!empty($_POST['entries']) && !empty($_POST['action'])) { - try { - foreach ($_POST['entries'] as $ns) { - $ac->set($cleaner->id, $_POST['action'], $ns); + public static function process(): bool + { + if (!static::$init || !dcCore::app()->plugins->moduleExists('Uninstaller')) { + return false; } - dcAdminNotices::addSuccessNotice(__('Action successfuly excecuted')); - dcCore::app()->adminurl->redirect( - 'admin.plugin.' . basename(__DIR__), - ['part' => $cleaner->id] + + $vars = ManageVars::init(); + + if (!empty($_POST['option-action'])) { + dcCore::app()->blog?->settings->get(My::id())->dropEvery( + 'dcproperty_hide' + ); + dcCore::app()->blog?->settings->get(My::id())->put( + 'dcproperty_hide', + !empty($_POST['dcproperty_hide']), + 'boolean', + 'Hide Dotclear default properties', + true, + true + ); + dcPage::addSuccessNotice(__('Configuration successfuly updated')); + dcCore::app()->adminurl?->redirect( + 'admin.plugin.' . My::id(), + ['part' => $vars->cleaner?->id] + ); + } + + if (!empty($vars->entries) && !empty($vars->action)) { + try { + foreach ($vars->entries as $ns) { + $vars->cleaners->execute($vars->cleaner?->id, $vars->action, $ns); + } + dcPage::addSuccessNotice(__('Action successfuly excecuted')); + dcCore::app()->adminurl?->redirect( + 'admin.plugin.' . My::id(), + ['part' => $vars->cleaner?->id] + ); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + } + + return true; + } + + public static function render(): void + { + if (!static::$init) { + return; + } + + $vars = ManageVars::init(); + + dcPage::openModule( + My::name(), + dcPage::cssModuleLoad(My::id() . '/css/backend.css') . + dcPage::jsModuleLoad(My::id() . '/js/backend.js') ); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} -# Display -echo '' . __('Advanced cleaner') . '' . -dcPage::cssLoad(dcPage::getPF(basename(__DIR__) . '/style.css')) . -dcPage::jsLoad(dcPage::getPF(basename(__DIR__) . '/js/index.js')); + # --BEHAVIOR-- dcAdvancedCleanerAdminHeader + dcCore::app()->callBehavior('dcAdvancedCleanerAdminHeader'); -# --BEHAVIOR-- dcAdvancedCleanerAdminHeader -dcCore::app()->callBehavior('dcAdvancedCleanerAdminHeader'); - -echo '' . -dcPage::breadcrumb([ - __('Plugins') => '', - __('Advanced cleaner') => '', -]) . -dcPage::notices() . - -'
' . -'

' . -form::combo('part', $select_menu, $cleaner->id) . ' ' . -'' . -form::hidden('p', basename(__DIR__)) . '

' . -'
' . - -'

' . $cleaner->name . '

' . $cleaner->desc . '

'; - -$rs = $cleaner->get(); - -if (empty($rs)) { - echo '

' . __('There is nothing to display') . '

'; -} else { - echo - '
' . - '
' . - '' . - '' . - ''; - - foreach ($rs as $k => $v) { - $offline = in_array($v['key'], $cleaner->official()); - - if ($offline && dcCore::app()->blog->settings->__get(basename(__DIR__))->dcAdvancedCleaner_dcproperty_hide) { - continue; - } echo - '' . - ' ' . - '' . - '' . - ''; + dcPage::breadcrumb([ + __('Plugins') => '', + My::name() => '', + ]) . + dcPage::notices(); + + if ($vars->cleaner === null) { + dcPage::closeModule(); + + return; + } + + echo + (new Form('parts_menu'))->method('get')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ + (new Para())->class('anchor-nav')->items([ + (new Label(__('Goto:'), Label::OUTSIDE_LABEL_BEFORE))->for('part')->class('classic'), + (new Select(['part', 'select_part']))->default($vars->cleaner->id)->items($vars->combo), + (new Submit('go'))->value(__('Ok')), + (new Hidden(['p'], My::id())), + ]), + ])->render() . + + '

' . $vars->cleaner->name . '

' . $vars->cleaner->desc . '

'; + + $rs = $vars->cleaner->values(); + + if (empty($rs)) { + echo '

' . __('There is nothing to display') . '

'; + } else { + $combo_actions = []; + foreach ($vars->cleaner->actions as $descriptor) { + // exception + if ($descriptor->id == 'delete_related') { + continue; + } + $combo_actions[$descriptor->select] = $descriptor->id; + } + + echo + '' . + '
' . + '
' . sprintf(__('There are %s %s'), count($rs), __($cleaner->id)) . '
' . __('Name') . '' . __('Objects') . '
' . - form::checkbox( - ['entries[' . $k . ']', 'entries_' . $k], - html::escapeHTML($v['key']) - ) . '' . $v['value'] . '
' . + '' . + ''; + + foreach ($rs as $k => $v) { + $distrib = in_array($v['key'], $vars->cleaner->distributed()); + + if ($distrib && dcCore::app()->blog?->settings->get(My::id())->get('dcproperty_hide')) { + continue; + } + echo + '' . + ' ' . + '' . + '' . + '' . + ''; + } + + echo + '
' . sprintf(__('There are %s entries'), count($rs)) . '
' . __('Name') . '' . __('Objects') . '
' . + (new Checkbox(['entries[' . $k . ']', 'entries_' . $k]))->value(Html::escapeHTML($v['key']))->render() . + '' . + (new Label($v['key'], Label::OUTSIDE_LABEL_AFTER))->for('entries_' . $k)->class('classic')->render() . + '' . $v['value'] . '' . ($distrib ? + '' .
+                    __('Values from official distribution') . '' + : '') . '
' . + (new Para())->items([ + (new Label(__('Action on selected rows:'), Label::OUTSIDE_LABEL_BEFORE))->for('select_action'), + (new Select(['action', 'select_action']))->items($combo_actions), + (new Submit('do-action'))->value(__('ok')), + (new Hidden(['p'], My::id())), + (new Hidden(['part'], $vars->cleaner->id)), + dcCore::app()->formNonce(false), + ])->render() . + '

' . + __('Beware: All actions done here are irreversible and are directly applied') . + '

' . + '
'; + } + + echo + (new Form('option'))->method('post')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ + (new Para())->items([ + (new Submit('option-action'))->value(dcCore::app()->blog?->settings->get(My::id())->get('dcproperty_hide') ? __('Show Dotclear default properties') : __('Hide Dotclear default properties')), + (new Hidden('dcproperty_hide', (string) (int) !dcCore::app()->blog->settings->get(My::id())->get('dcproperty_hide'))), + (new Hidden(['p'], My::id())), + (new Hidden(['part'], $vars->cleaner->id)), + dcCore::app()->formNonce(false), + ]), + ])->render(); + + dcPage::closeModule(); } - echo - '' . - '

' . __('Action on selected rows:') . ' ' . - form::combo(['action'], array_flip($cleaner->getActions())) . - '' . - form::hidden(['p'], basename(__DIR__)) . - form::hidden(['part'], $cleaner->id) . - dcCore::app()->formNonce() . '

' . - '

' . - __('Beware: All actions done here are irreversible and are directly applied') . - '

' . - ''; } - -if (dcCore::app()->blog->settings->__get(basename(__DIR__))->dcAdvancedCleaner_dcproperty_hide) { - echo '

' . - __('Default values of Dotclear are hidden. You can change this in settings') . - '

'; -} - -dcPage::helpBlock('dcAdvancedCleaner'); - -echo ''; diff --git a/src/ManageVars.php b/src/ManageVars.php new file mode 100644 index 0000000..c1e7129 --- /dev/null +++ b/src/ManageVars.php @@ -0,0 +1,72 @@ +cleaners = Uninstaller::instance()->cleaners; + + $entries = $_REQUEST['entries'] ?? []; + $action = $_POST['action'] ?? ''; + + $cleaner = null; + $combo = []; + foreach ($this->cleaners->dump() as $k) { + $combo[$k->name] = $k->id; + if ($k->id == $_REQUEST['part']) { + $cleaner = $k; + } + } + if ($cleaner === null) { + if (!($cleaner = $this->cleaners->get('caches'))) { + throw new Exception(__('Failed to load cleaner')); + } + } + + $this->cleaner = $cleaner; + $this->entries = is_array($entries) ? $entries : []; + $this->action = is_string($action) ? $action : ''; + $this->combo = $combo; + } + + public static function init(): ManageVars + { + if (!(self::$container instanceof self)) { + self::$container = new self(); + } + + return self::$container; + } +} diff --git a/src/My.php b/src/My.php new file mode 100644 index 0000000..3461769 --- /dev/null +++ b/src/My.php @@ -0,0 +1,58 @@ +plugins->moduleInfo(self::id(), 'name')); + } + + /** + * This plugin root + */ + public static function root(): string + { + return dirname(__DIR__); + } + + /** + * Check php version + */ + public static function phpCompliant(): bool + { + return version_compare(phpversion(), self::PHP_MIN, '>='); + } +} diff --git a/src/Prepend.php b/src/Prepend.php index d4b696a..eae5e72 100644 --- a/src/Prepend.php +++ b/src/Prepend.php @@ -10,40 +10,48 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} - -# dcac class -Clearbricks::lib()->autoload([ - 'advancedCleaner' => __DIR__ . '/inc/class.advanced.cleaner.php', - 'dcAdvancedCleaner' => __DIR__ . '/inc/class.dc.advanced.cleaner.php', - 'behaviorsDcAdvancedCleaner' => __DIR__ . '/inc/lib.dc.advanced.cleaner.behaviors.php', - 'dcUninstaller' => __DIR__ . '/inc/class.dc.uninstaller.php', - 'dcAdvancedCleanerActivityReportBehaviors' => __DIR__ . '/inc/lib.dc.advanced.cleaner.activityreport.php', -]); - -# cleaners class -Clearbricks::lib()->autoload([ - 'advancedCleanerVersions' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerSettings' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerTables' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerThemes' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerPlugins' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerCaches' => __DIR__ . '/inc/lib.advanced.cleaner.php', - 'advancedCleanerVars' => __DIR__ . '/inc/lib.advanced.cleaner.php', -]); - -dcCore::app()->addBehaviors([ - 'advancedCleanerAdd' => ['advancedCleanerVersions', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerSettings', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerTables', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerThemes', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerPlugins', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerCaches', 'create'], - 'advancedCleanerAdd' => ['advancedCleanerVars', 'create'], -]); - -if (defined('ACTIVITY_REPORT_V2')) { - dcAdvancedCleanerActivityReportBehaviors::add(); +declare(strict_types=1); + +namespace Dotclear\Plugin\dcAdvancedCleaner; + +use dcCore; +use dcNsProcess; + +class Prepend extends dcNsProcess +{ + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && dcCore::app()->auth?->isSuperAdmin(); + + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; + } + + if (defined('ACTIVITY_REPORT_V2')) { + dcCore::app()->activityReport->addGroup( + My::id(), + __('Plugin dcAdvancedCleaner') + ); + + dcCore::app()->activityReport->addAction( + My::id(), + 'maintenance', + __('Maintenance'), + __('New action from dcAdvancedCleaner has been made with type="%s", action="%s", ns="%s".'), + 'dcAdvancedCleanerBeforeAction', + function ($type, $action, $ns) { + dcCore::app()->activityReport->addLog(My::id(), 'maintenance', [$type,$action, $ns]); + } + ); + } + + return true; + } } diff --git a/style.css b/style.css deleted file mode 100644 index 1ff8cfe..0000000 --- a/style.css +++ /dev/null @@ -1,10 +0,0 @@ -.listDcAdvancedCleaner { - padding:10px; - margin:10px 10px 0 0; -} -.bombDcAdvancedCleaner { - padding:14px 0 2px 36px; - background:url(index.php?pf=dcAdvancedCleaner/icon-b.png) no-repeat; -} -.offline {background: url("index.php?pf=dcAdvancedCleaner/dotclear.png") no-repeat scroll 18em 7px;} -.offline label{font-weight:bold;color:#c44d58;} \ No newline at end of file