From 06cc847af8053dd4d14d83b2b5263366db9de570 Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Fri, 2 Dec 2022 11:18:09 +0100 Subject: [PATCH] first draft --- _admin.php | 139 +++++++++++++++++++++++++++++++++ _define.php | 30 +++++++ _prepend.php | 19 +++++ inc/class.csv.store.parser.php | 57 ++++++++++++++ inc/class.csv.store.php | 82 +++++++++++++++++++ inc/class.csv.store.reader.php | 38 +++++++++ 6 files changed, 365 insertions(+) create mode 100644 _admin.php create mode 100644 _define.php create mode 100644 _prepend.php create mode 100644 inc/class.csv.store.parser.php create mode 100644 inc/class.csv.store.php create mode 100644 inc/class.csv.store.reader.php diff --git a/_admin.php b/_admin.php new file mode 100644 index 0000000..463c2bd --- /dev/null +++ b/_admin.php @@ -0,0 +1,139 @@ +auth->isSuperAdmin()) { + return null; +} + +# admin behaviors +$core->addBehavior('pluginsToolsTabs', ['csvBehaviors', 'pluginsToolsTabs']); +$core->addBehavior('themesToolsTabs', ['csvBehaviors', 'themesToolsTabs']); + +class csvBehaviors +{ + # admin plugins page tab + public static function pluginsToolsTabs(dcCore $core): void + { + self::modulesToolsTabs($core, $core->plugins, explode(',', DC_DISTRIB_PLUGINS), $core->adminurl->get('admin.plugins') . '#csv'); + } + + # admin themes page tab + public static function themesToolsTabs(dcCore $core): void + { + self::modulesToolsTabs($core, $core->themes, explode(',', DC_DISTRIB_THEMES), $core->adminurl->get('admin.blog.theme') . '#csv'); + } + + # generic page tab + protected static function modulesToolsTabs(dcCore $core, dcModules $modules, array $excludes, string $page_url): void + { + $list = []; + foreach (array_merge($modules->getModules(), $modules->getDisabledModules()) as $id => $module) { + if (!in_array($id, $excludes)) { + $list[$id] = $module; + } + } + + echo + '
' . + '

' . __('Check store version') . '

'; + + if (!count($list)) { + echo + '
' . __('There is no module to check') . '
' . + '
'; + + return; + } + + echo + '
' . + '

' . + $core->formNonce() . '

' . + '
'; + + if (!empty($_POST['csvcheck'])) { + $store = new csvStore($modules, dcCore::app()->blog->settings->system->store_plugin_url, true); + self::modulesList($list, $store->get(true)); + } + + echo + ''; + } + + private static function modulesList($modules, $repos) + { + if (empty($repos)) { + return; + } + + echo + '
' . + '' . + '' . + '' . + '' . + '' . + ''; + + foreach ($modules as $id => $module) { + + $default_icon = false; + + if (file_exists($module['root'] . '/icon.svg')) { + $icon = dcPage::getPF($id . '/icon.svg'); + } elseif (file_exists($module['root'] . '/icon.png')) { + $icon = dcPage::getPF($id . '/icon.png'); + } else { + $icon = 'images/module.svg'; + $default_icon = true; + } + if (file_exists($module['root'] . '/icon-dark.svg')) { + $icon = [$icon, dcPage::getPF($id . '/icon-dark.svg')]; + } elseif (file_exists($module['root'] . '/icon-dark.png')) { + $icon = [$icon, dcPage::getPF($id . '/icon-dark.png')]; + } elseif ($default_icon) { + $icon = [$icon, 'images/module-dark.svg']; + } + + echo + '' . + '' . + '' . + '' . + ''; + } else { + echo + '' . + ''; + } + + echo + ''; + } + + echo + '
' . __('Name') . '' . __('Current version') . '' . __('Latest version') . '' . __('Written for Dotclear') . '
' . + dcAdminHelper::adminIcon($icon, false, html::escapeHTML($id), html::escapeHTML($id)) . + '' . + html::escapeHTML($module['name']) . ($id != $module['name'] ? sprintf(__(' (%s)'), $id) : '') . + ''; + + if (isset($repos[$id])) { + echo + '' . html::escapeHTML($repos[$id]['current_version']) . '' . html::escapeHTML($repos[$id]['version']) . '' . html::escapeHTML($repos[$id]['dc_min']) . '' . html::escapeHTML($module['version']) . '' . html::escapeHTML(__('No version available on store')) . '
'; + } +} diff --git a/_define.php b/_define.php new file mode 100644 index 0000000..51e4584 --- /dev/null +++ b/_define.php @@ -0,0 +1,30 @@ +registerModule( + 'Check store version', + 'Check plugins and themes available version before update', + 'Jean-Christian Denis and Contributors', + '0.1-dev', + [ + 'requires' => [['core', '2.19']], + 'permissions' => null, + 'type' => 'plugin', + 'support' => 'https://github.com/JcDenis/checkStoreVersion', + 'details' => 'https://plugins.dotaddict.org/dc2/details/checkStoreVersion', + 'repository' => 'https://raw.githubusercontent.com/JcDenis/checkStoreVersion/master/' + ] +); diff --git a/_prepend.php b/_prepend.php new file mode 100644 index 0000000..ba62bd6 --- /dev/null +++ b/_prepend.php @@ -0,0 +1,19 @@ +xml->module)) { + return; + } + + foreach ($this->xml->module as $i) { + $attrs = $i->attributes(); + + $item = []; + + # DC/DA shared markers + $item['id'] = (string) $attrs['id']; + $item['file'] = (string) $i->file; + $item['label'] = (string) $i->name; // deprecated + $item['name'] = (string) $i->name; + $item['version'] = (string) $i->version; + $item['author'] = (string) $i->author; + $item['desc'] = (string) $i->desc; + + # DA specific markers + $item['dc_min'] = (string) $i->children(self::$bloc)->dcmin; + $item['details'] = (string) $i->children(self::$bloc)->details; + $item['section'] = (string) $i->children(self::$bloc)->section; + $item['support'] = (string) $i->children(self::$bloc)->support; + $item['sshot'] = (string) $i->children(self::$bloc)->sshot; + + $tags = []; + foreach ($i->children(self::$bloc)->tags as $t) { + $tags[] = (string) $t->tag; + } + $item['tags'] = implode(', ', $tags); + + # No more filters here, return all modules + $this->items[$item['id']] = $item; + } + } +} \ No newline at end of file diff --git a/inc/class.csv.store.php b/inc/class.csv.store.php new file mode 100644 index 0000000..e719258 --- /dev/null +++ b/inc/class.csv.store.php @@ -0,0 +1,82 @@ +xml_url) { + return false; + } + + try { + $parser = DC_STORE_NOT_UPDATE ? false : csvStoreReader::quickParse($this->xml_url, DC_TPL_CACHE, $force); + } catch (Exception $e) { + return false; + } + + $raw_datas = !$parser ? [] : $parser->getModules(); + + uasort($raw_datas, fn ($a, $b) => strtolower($a['id']) <=> strtolower($b['id'])); + + $updates = []; + $current = array_merge($this->modules->getModules(), $this->modules->getDisabledModules()); + foreach ($current as $p_id => $p_infos) { + # non privileged user has no info + if (!is_array($p_infos)) { + continue; + } + # main repository + if (isset($raw_datas[$p_id])) { + if (dcUtils::versionsCompare($raw_datas[$p_id]['version'], $p_infos['version'], '>=')) { + $updates[$p_id] = $raw_datas[$p_id]; + $updates[$p_id]['root'] = $p_infos['root']; + $updates[$p_id]['root_writable'] = $p_infos['root_writable']; + $updates[$p_id]['current_version'] = $p_infos['version']; + } + unset($raw_datas[$p_id]); + } + # per module third-party repository + if (!empty($p_infos['repository']) && DC_ALLOW_REPOSITORIES) { + try { + $dcs_url = substr($p_infos['repository'], -12, 12) == '/dcstore.xml' ? $p_infos['repository'] : http::concatURL($p_infos['repository'], 'dcstore.xml'); + $dcs_parser = csvStoreReader::quickParse($dcs_url, DC_TPL_CACHE, $force); + if ($dcs_parser !== false) { + $dcs_raw_datas = $dcs_parser->getModules(); + if (isset($dcs_raw_datas[$p_id]) && dcUtils::versionsCompare($dcs_raw_datas[$p_id]['version'], $p_infos['version'], '>=')) { + if (!isset($updates[$p_id]) || dcUtils::versionsCompare($dcs_raw_datas[$p_id]['version'], $updates[$p_id]['version'], '>=')) { + $dcs_raw_datas[$p_id]['repository'] = true; + $updates[$p_id] = $dcs_raw_datas[$p_id]; + $updates[$p_id]['root'] = $p_infos['root']; + $updates[$p_id]['root_writable'] = $p_infos['root_writable']; + $updates[$p_id]['current_version'] = $p_infos['version']; + } + } + } + } catch (Exception $e) { + } + } + } + + $this->data = [ + 'new' => $raw_datas, + 'update' => $updates, + ]; + + return true; + } +} \ No newline at end of file diff --git a/inc/class.csv.store.reader.php b/inc/class.csv.store.reader.php new file mode 100644 index 0000000..c12234d --- /dev/null +++ b/inc/class.csv.store.reader.php @@ -0,0 +1,38 @@ +validators = []; + + if (!$this->getModulesXML($url) || $this->getStatus() != '200') { + return false; + } + + return new csvStoreParser($this->getContent()); + } + + # overwrite dcStoreReader to remove cache and use mvStoreParser + public static function quickParse($url, $cache_dir = null, $force = true) + { + $parser = new self(); + + return $parser->parse($url); + } +}