From dbebb5663cb6f2cecdf0f1427a371b2f63dcb18f Mon Sep 17 00:00:00 2001 From: aB0t Date: Mon, 23 Jun 2025 17:02:17 +0000 Subject: [PATCH] Release of v5.1.1-beta3 Fixes issue with loading the Component Builder Wiki. Adds advanced version update notice to the Component Builder Dashboard. Completely refactors the class that builds the Component Dashboard. #1134. --- CHANGELOG.md | 10 +- ComponentbuilderInstallerScript.php | 2 +- README.md | 6 +- admin/README.txt | 6 +- admin/compiler/joomla_4/DASH_MODEL.php | 424 ++++---- admin/compiler/joomla_4/DASH_VIEW_HTML.php | 62 +- .../en-GB/en-GB.com_componentbuilder.ini | 10 +- admin/sql/install.mysql.utf8.sql | 4 +- admin/src/Controller/AjaxController.php | 50 - admin/src/Model/AjaxModel.php | 174 +--- admin/src/Model/ComponentbuilderModel.php | 934 ++++++++++-------- admin/src/View/Componentbuilder/HtmlView.php | 62 +- componentbuilder.xml | 6 +- componentbuilder_update_server.xml | 10 +- .../VDM.Joomla.Gitea/src/Repository/Tags.php | 3 +- .../VDM.Joomla.Gitea/src/Repository/Wiki.php | 56 +- .../VDM.Joomla.Github/src/Abstraction/Api.php | 31 +- .../VDM.Joomla.Github/src/Factory.php | 51 + .../src/Repository/Contents.php | 2 +- .../VDM.Joomla.Github/src/Repository/Tags.php | 186 ++++ .../VDM.Joomla.Github/src/Repository/Wiki.php | 166 ++++ .../src/Service/Utilities.php | 5 +- .../Compiler/Builder/PermissionDashboard.php | 24 +- .../Componentbuilder/Power/Service/Github.php | 42 + .../src/Componentbuilder/Remote/Version.php | 386 ++++++++ .../src/Componentbuilder/Remote/index.html | 1 + .../Git/Repository/TagsInterface.php | 107 ++ .../Git/Repository/WikiInterface.php | 135 +++ 28 files changed, 2067 insertions(+), 888 deletions(-) create mode 100644 libraries/vendor_jcb/VDM.Joomla.Github/src/Factory.php create mode 100644 libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Tags.php create mode 100644 libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Wiki.php create mode 100644 libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/Version.php create mode 100644 libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/index.html create mode 100644 libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/TagsInterface.php create mode 100644 libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/WikiInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 25818b0d3..cd7965ac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -# v5.1.1-beta2 - -- Enhance operator support in dynamic get system. Relates to issue #1226. +# v5.1.1-beta3 +- Fixes issue with loading the Component Builder Wiki. +- Adds advanced version update notice to the Component Builder Dashboard. +- Completely refactors the class that builds the Component Dashboard. #1134 # v5.1.1-beta @@ -20,7 +21,8 @@ - Refactor initialization flow to accommodate future scalability and integration with all designated areas. - Refactor the Creator Builders class. - Refactor the FieldString and FieldXML classes. -- Add JCB new package engine. +- Add JCB new package engine. +- Enhance operator support in dynamic get system. Relates to issue #1226. # v5.1.0 diff --git a/ComponentbuilderInstallerScript.php b/ComponentbuilderInstallerScript.php index a88965991..806b5ccfe 100644 --- a/ComponentbuilderInstallerScript.php +++ b/ComponentbuilderInstallerScript.php @@ -3292,7 +3292,7 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface echo '
-

Upgrade to Version 5.1.1-beta2 Was Successful! Let us know if anything is not working as expected.

'; +

Upgrade to Version 5.1.1-beta3 Was Successful! Let us know if anything is not working as expected.

'; // Add/Update component in the action logs extensions table. $this->setActionLogsExtensions(); diff --git a/README.md b/README.md index 273c9dc04..5b810745a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is a professional-grade [Joomla 5.x](https://extensions.joomla.org/extensio JCB generates native Joomla components, plugins, and modules for Joomla 3.x, 4.x, and 5.x — and is already prepared for Joomla 6. Every compiled project is tailored for the specific version without needing backward compatibility plugins. With integrated version-aware compiling, smart boilerplating, and Git-powered project syncing, JCB is much more than a code generator—it's a **full-stack development pipeline for Joomla extensions**. -You can install this component easily. The latest release (**5.1.1-beta2**) is available on [Releases](https://git.vdm.dev/joomla/pkg-component-builder/releases) and updated frequently with full source access. +You can install this component easily. The latest release (**5.1.1-beta3**) is available on [Releases](https://git.vdm.dev/joomla/pkg-component-builder/releases) and updated frequently with full source access. Upgrades are seamless through Joomla’s built-in extension update mechanism. @@ -229,9 +229,9 @@ JCB is developed by developers for developers. Its purpose is to democratize hig * **Company:** [Vast Development Method](https://dev.vdm.io) * **Author:** [Llewellyn van der Merwe](mailto:joomla@vdm.io) * **Component:** [Component Builder](https://git.vdm.dev/joomla/Component-Builder) -* **Created:** 30th April, 2015 · **Last Build:** 19th June, 2025 · **Version:** 5.1.1-beta2 +* **Created:** 30th April, 2015 · **Last Build:** 23rd June, 2025 · **Version:** 5.1.1-beta3 * **License:** GNU General Public License version 2 or later; see LICENSE.txt · **Copyright:** Copyright (C) 2015 Vast Development Method. All rights reserved. -* **Lines:** 1086810 · **Fields:** 2096 · **Files:** 7419 · **Folders:** 724 +* **Lines:** 1090382 · **Fields:** 2096 · **Files:** 7450 · **Folders:** 725 > Generated with [JCB](https://www.joomlacomponentbuilder.com) — The Smartest Way to Build Joomla Extensions. diff --git a/admin/README.txt b/admin/README.txt index 273c9dc04..5b810745a 100644 --- a/admin/README.txt +++ b/admin/README.txt @@ -9,7 +9,7 @@ This is a professional-grade [Joomla 5.x](https://extensions.joomla.org/extensio JCB generates native Joomla components, plugins, and modules for Joomla 3.x, 4.x, and 5.x — and is already prepared for Joomla 6. Every compiled project is tailored for the specific version without needing backward compatibility plugins. With integrated version-aware compiling, smart boilerplating, and Git-powered project syncing, JCB is much more than a code generator—it's a **full-stack development pipeline for Joomla extensions**. -You can install this component easily. The latest release (**5.1.1-beta2**) is available on [Releases](https://git.vdm.dev/joomla/pkg-component-builder/releases) and updated frequently with full source access. +You can install this component easily. The latest release (**5.1.1-beta3**) is available on [Releases](https://git.vdm.dev/joomla/pkg-component-builder/releases) and updated frequently with full source access. Upgrades are seamless through Joomla’s built-in extension update mechanism. @@ -229,9 +229,9 @@ JCB is developed by developers for developers. Its purpose is to democratize hig * **Company:** [Vast Development Method](https://dev.vdm.io) * **Author:** [Llewellyn van der Merwe](mailto:joomla@vdm.io) * **Component:** [Component Builder](https://git.vdm.dev/joomla/Component-Builder) -* **Created:** 30th April, 2015 · **Last Build:** 19th June, 2025 · **Version:** 5.1.1-beta2 +* **Created:** 30th April, 2015 · **Last Build:** 23rd June, 2025 · **Version:** 5.1.1-beta3 * **License:** GNU General Public License version 2 or later; see LICENSE.txt · **Copyright:** Copyright (C) 2015 Vast Development Method. All rights reserved. -* **Lines:** 1086810 · **Fields:** 2096 · **Files:** 7419 · **Folders:** 724 +* **Lines:** 1090382 · **Fields:** 2096 · **Files:** 7450 · **Folders:** 725 > Generated with [JCB](https://www.joomlacomponentbuilder.com) — The Smartest Way to Build Joomla Extensions. diff --git a/admin/compiler/joomla_4/DASH_MODEL.php b/admin/compiler/joomla_4/DASH_MODEL.php index 3ed7bfedf..90faaf1fe 100644 --- a/admin/compiler/joomla_4/DASH_MODEL.php +++ b/admin/compiler/joomla_4/DASH_MODEL.php @@ -27,6 +27,24 @@ namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Administrator */ class ###Component###Model extends ListModel { + /** + * Represents the current user object. + * + * @var User The user object representing the current user. + * @since 3.2.0 + */ + protected User $user; + + /** + * View groups of this component + * + * @var array + * @since 5.1.1 + */ + protected array $viewGroups = [ + 'main' => [###DASHBOARDICONS###], + ]; +###DASHBOARDICONACCESS### /** * The styles array. * @@ -48,199 +66,50 @@ class ###Component###Model extends ListModel 'administrator/components/com_###component###/assets/js/admin.js' ]; - public function getIcons() + /** + * Constructor + * + * @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request). + * @param ?MVCFactoryInterface $factory The factory. + * + * @since 1.6 + * @throws \Exception + */ + public function __construct($config = [], MVCFactoryInterface $factory = null) { - // load user for access menus - $user = Joomla___39403062_84fb_46e0_bac4_0023f766e827___Power::getApplication()->getIdentity(); - // reset icon array - $icons = []; - // view groups array - $viewGroups = array( - 'main' => array(###DASHBOARDICONS###) - );###DASHBOARDICONACCESS### - // loop over the $views - foreach($viewGroups as $group => $views) + parent::__construct($config, $factory); + + $this->user ??= $this->getCurrentUser(); + } + + /** + * Get dashboard icons, grouped by view sections. + * + * @return array> + * @since 5.1.1 + */ + public function getIcons(): array + { + $icons = []; + + foreach ($this->viewGroups as $group => $views) { - $i = 0; - if (Super___0a59c65c_9daf_4bc9_baf4_e063ff9e6a8a___Power::check($views)) + if (!Super___0a59c65c_9daf_4bc9_baf4_e063ff9e6a8a___Power::check($views)) { - foreach($views as $view) + $icons[$group][] = false; + continue; + } + + foreach ($views as $view) + { + $icon = $this->buildIconObject($view); + if ($icon !== null) { - $add = false; - // external views (links) - if (strpos($view,'||') !== false) - { - $dwd = explode('||', $view); - if (count($dwd) == 3) - { - list($type, $name, $url) = $dwd; - $viewName = $name; - $alt = $name; - $url = $url; - $image = $name . '.' . $type; - $name = 'COM_###COMPONENT###_DASHBOARD_' . Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name,'U'); - } - } - // internal views - elseif (strpos($view,'.') !== false) - { - $dwd = explode('.', $view); - if (count($dwd) == 3) - { - list($type, $name, $action) = $dwd; - } - elseif (count($dwd) == 2) - { - list($type, $name) = $dwd; - $action = false; - } - if ($action) - { - $viewName = $name; - switch($action) - { - case 'add': - $url = 'index.php?option=com_###component###&view=' . $name . '&layout=edit'; - $image = $name . '_' . $action. '.' . $type; - $alt = $name . ' ' . $action; - $name = 'COM_###COMPONENT###_DASHBOARD_'.Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name,'U').'_ADD'; - $add = true; - break; - default: - // check for new convention (more stable) - if (strpos($action, '_qpo0O0oqp_') !== false) - { - list($action, $extension) = (array) explode('_qpo0O0oqp_', $action); - $extension = str_replace('_po0O0oq_', '.', $extension); - } - else - { - $extension = 'com_###component###.' . $name; - } - $url = 'index.php?option=com_categories&view=categories&extension=' . $extension; - $image = $name . '_' . $action . '.' . $type; - $alt = $viewName . ' ' . $action; - $name = 'COM_###COMPONENT###_DASHBOARD_' . Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name,'U') . '_' . Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($action,'U'); - break; - } - } - else - { - $viewName = $name; - $alt = $name; - $url = 'index.php?option=com_###component###&view=' . $name; - $image = $name . '.' . $type; - $name = 'COM_###COMPONENT###_DASHBOARD_' . Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name,'U'); - $hover = false; - } - } - else - { - $viewName = $view; - $alt = $view; - $url = 'index.php?option=com_###component###&view=' . $view; - $image = $view . '.png'; - $name = ucwords($view).'

'; - $hover = false; - } - // first make sure the view access is set - if (Super___0a59c65c_9daf_4bc9_baf4_e063ff9e6a8a___Power::check($viewAccess)) - { - // setup some defaults - $dashboard_add = false; - $dashboard_list = false; - $accessTo = ''; - $accessAdd = ''; - // access checking start - $accessCreate = (isset($viewAccess[$viewName.'.create'])) ? Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($viewAccess[$viewName.'.create']):false; - $accessAccess = (isset($viewAccess[$viewName.'.access'])) ? Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($viewAccess[$viewName.'.access']):false; - // set main controllers - $accessDashboard_add = (isset($viewAccess[$viewName.'.dashboard_add'])) ? Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($viewAccess[$viewName.'.dashboard_add']):false; - $accessDashboard_list = (isset($viewAccess[$viewName.'.dashboard_list'])) ? Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($viewAccess[$viewName.'.dashboard_list']):false; - // check for adding access - if ($add && $accessCreate) - { - $accessAdd = $viewAccess[$viewName.'.create']; - } - elseif ($add) - { - $accessAdd = 'core.create'; - } - // check if access to view is set - if ($accessAccess) - { - $accessTo = $viewAccess[$viewName.'.access']; - } - // set main access controllers - if ($accessDashboard_add) - { - $dashboard_add = $user->authorise($viewAccess[$viewName.'.dashboard_add'], 'com_###component###'); - } - if ($accessDashboard_list) - { - $dashboard_list = $user->authorise($viewAccess[$viewName.'.dashboard_list'], 'com_###component###'); - } - if (Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessAdd) && Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessTo)) - { - // check access - if($user->authorise($accessAdd, 'com_###component###') && $user->authorise($accessTo, 'com_###component###') && $dashboard_add) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - elseif (Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessTo)) - { - // check access - if($user->authorise($accessTo, 'com_###component###') && $dashboard_list) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - elseif (Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessAdd)) - { - // check access - if($user->authorise($accessAdd, 'com_###component###') && $dashboard_add) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - else - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - else - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - $i++; + $icons[$group][] = $icon; } } - else - { - $icons[$group][$i] = false; - } } + return $icons; } @@ -286,5 +155,188 @@ class ###Component###Model extends ListModel public function setScript(string $path): void { $this->scripts[] = $path; + } + + /** + * Build a single dashboard icon if access is granted. + * + * @param string $view The view string to parse. + * + * @return \stdClass|null The icon object or null if access denied. + * @since 5.1.1 + */ + protected function buildIconObject(string $view): ?\stdClass + { + $parsed = $this->parseViewDefinition($view); + if (!$parsed) + { + return null; + } + + [ + 'type' => $type, + 'name' => $name, + 'url' => $url, + 'image' => $image, + 'alt' => $alt, + 'viewName' => $viewName, + 'add' => $add, + ] = $parsed; + + if (!$this->hasAccessToView($viewName, $add)) + { + return null; + } + + return $this->createIconObject($url, $name, $image, $alt); + } + + /** + * Parse a view string into structured components. + * + * @param string $view The view definition string. + * + * @return array|null Parsed values or null on failure. + * @since 5.1.1 + */ + protected function parseViewDefinition(string $view): ?array + { + $add = false; + + if (strpos($view, '||') !== false) + { + $parts = explode('||', $view); + if (count($parts) === 3) + { + [$type, $name, $url] = $parts; + return [ + 'type' => $type, + 'name' => 'COM_###COMPONENT###_DASHBOARD_' . Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name, 'U'), + 'url' => $url, + 'image' => "{$name}.{$type}", + 'alt' => $name, + 'viewName' => $name, + 'add' => false, + ]; + } + } + + if (strpos($view, '.') !== false) + { + $parts = explode('.', $view); + $type = $parts[0] ?? ''; + $name = $parts[1] ?? ''; + $action = $parts[2] ?? null; + $viewName = $name; + + if ($action) + { + if ($action === 'add') + { + $url = "index.php?option=com_###component###&view={$name}&layout=edit"; + $image = "{$name}_{$action}.{$type}"; + $alt = "{$name} {$action}"; + $name = 'COM_###COMPONENT###_DASHBOARD_' . + Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name, 'U') . '_ADD'; + $add = true; + } + else + { + if (strpos($action, '_qpo0O0oqp_') !== false) + { + [$action, $ext] = explode('_qpo0O0oqp_', $action); + $extension = str_replace('_po0O0oq_', '.', $ext); + } + else + { + $extension = "com_###component###.{$name}"; + } + $url = "index.php?option=com_categories&view=categories&extension={$extension}"; + $image = "{$name}_{$action}.{$type}"; + $alt = "{$name} {$action}"; + $name = 'COM_###COMPONENT###_DASHBOARD_' . + Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name, 'U') . '_' . + Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($action, 'U'); + } + } + else + { + $url = "index.php?option=com_###component###&view={$name}"; + $image = "{$name}.{$type}"; + $alt = $name; + $name = 'COM_###COMPONENT###_DASHBOARD_' . + Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::safe($name, 'U'); + } + + return compact('type', 'name', 'url', 'image', 'alt', 'viewName', 'add'); + } + + return [ + 'type' => 'png', + 'name' => ucwords($view) . '

', + 'url' => "index.php?option=com_###component###&view={$view}", + 'image' => "{$view}.png", + 'alt' => $view, + 'viewName' => $view, + 'add' => false, + ]; + } + + /** + * Determine if the user has access to view or create the item. + * + * @param string $viewName The base name of the view. + * @param bool $add If this is an add-action. + * + * @return bool + * @since 5.1.1 + */ + protected function hasAccessToView(string $viewName, bool $add): bool + { + $viewAccess = $this->viewAccess; + $accessAdd = $add && isset($viewAccess["{$viewName}.create"]) + ? $viewAccess["{$viewName}.create"] + : ($add ? 'core.create' : ''); + + $accessTo = $viewAccess["{$viewName}.access"] ?? ''; + + $dashboardAdd = isset($viewAccess["{$viewName}.dashboard_add"]) && + $this->user->authorise($viewAccess["{$viewName}.dashboard_add"], 'com_###component###'); + + $dashboardList = isset($viewAccess["{$viewName}.dashboard_list"]) && + $this->user->authorise($viewAccess["{$viewName}.dashboard_list"], 'com_###component###'); + + if ($add && Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessAdd)) + { + return $this->user->authorise($accessAdd, 'com_###component###') && $dashboardAdd; + } + + if (Super___1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check($accessTo)) + { + return $this->user->authorise($accessTo, 'com_###component###') && $dashboardList; + } + + return !$accessTo && !$accessAdd; + } + + /** + * Create a \stdClass icon object. + * + * @param string $url Icon URL. + * @param string $name Language string or label. + * @param string $image Image filename. + * @param string $alt Alt text. + * + * @return \stdClass + * @since 5.1.1 + */ + protected function createIconObject(string $url, string $name, string $image, string $alt): \stdClass + { + $icon = new \stdClass; + $icon->url = $url; + $icon->name = $name; + $icon->image = $image; + $icon->alt = $alt; + return $icon; }###DASH_MODEL_METHODS### } diff --git a/admin/compiler/joomla_4/DASH_VIEW_HTML.php b/admin/compiler/joomla_4/DASH_VIEW_HTML.php index 452891aeb..18be64f1d 100644 --- a/admin/compiler/joomla_4/DASH_VIEW_HTML.php +++ b/admin/compiler/joomla_4/DASH_VIEW_HTML.php @@ -28,6 +28,60 @@ namespace ###NAMESPACEPREFIX###\Component\###ComponentNamespace###\Administrator #[\AllowDynamicProperties] class HtmlView extends BaseHtmlView { + /** + * @var array List of icon identifiers to render in the dashboard view. + * @since 1.6 + */ + public array $icons = []; + + /** + * @var array List of CSS file URLs to be added to the page. + * @since 4.3 + */ + public array $styles = []; + + /** + * @var array List of JavaScript file URLs to be included on the page. + * @since 4.3 + */ + public array $scripts = []; + + /** + * @var array List of contributor objects fetched via the helper. + * @since 1.6 + */ + public array $contributors = []; + + /** + * @var object|null The manifest metadata of the component as returned by `ComponentbuilderHelper::manifest()`. + * @since 1.6 + */ + public $manifest = null; + + /** + * @var string|null Markdown content of the component's wiki page. + * @since 1.6 + */ + public ?string $wiki = null; + + /** + * @var string|null The rendered or raw README markdown of the component. + * @since 1.6 + */ + public ?string $readme = null; + + /** + * @var string|null The current version of the component. + * @since 1.6 + */ + public ?string $version = null; + + /** + * @var string|null Help URL for the component dashboard view, if available. + * @since 1.6 + */ + public ?string $help_url = null; + /** * View display method * @@ -96,8 +150,12 @@ class HtmlView extends BaseHtmlView { // set page title $this->getDocument()->setTitle(Joomla___ba6326ef_cb79_4348_80f4_ab086082e3c5___Power::_('COM_###COMPONENT###_DASHBOARD')); - // add manifest to page JavaScript - $this->getDocument()->addScriptDeclaration("var manifest = JSON.parse(" . json_encode($this->manifest) . ");", "text/javascript"); + /** \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->getDocument()->getWebAssetManager(); + // Register the inline script with properly encoded JSON + $wa->addInlineScript( + 'var manifest = ' . json_encode($this->manifest, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ';' + ); // add styles foreach ($this->styles as $style) { diff --git a/admin/language/en-GB/en-GB.com_componentbuilder.ini b/admin/language/en-GB/en-GB.com_componentbuilder.ini index 0888ee935..1e59ba36e 100644 --- a/admin/language/en-GB/en-GB.com_componentbuilder.ini +++ b/admin/language/en-GB/en-GB.com_componentbuilder.ini @@ -3293,7 +3293,7 @@ COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_STATE_DESCRIPTION="Set the release COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_STATE_HINT="stable" COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_STATE_LABEL="Release State" COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_TARGET_VERSION_DESCRIPTION="Set the release target version" -COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_TARGET_VERSION_HINT="5\.[012]" +COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_TARGET_VERSION_HINT="5\.[0123]" COM_COMPONENTBUILDER_COMPONENT_UPDATES_UPDATE_TARGET_VERSION_LABEL="Update Server Release Target Version" COM_COMPONENTBUILDER_COMPONENT_UPDATES_URL_DESCRIPTION="Enter Download Link" COM_COMPONENTBUILDER_COMPONENT_UPDATES_URL_HINT="http://www.example.com/file.zip" @@ -5258,11 +5258,10 @@ COM_COMPONENTBUILDER_FREEOPEN="Free/Open" COM_COMPONENTBUILDER_FULL_WIDTH_IN_TAB="Full Width in Tab" COM_COMPONENTBUILDER_FUNCTION_NAME_ALREADY_TAKEN_PLEASE_TRY_AGAIN="Function name already taken, please try again." COM_COMPONENTBUILDER_GET_PACKAGE="Get Package" -COM_COMPONENTBUILDER_GET_TOKEN="Get Token" -COM_COMPONENTBUILDER_GET_TOKEN_FROM_VDM_TO_GET_UPDATE_NOTICE_AND_ADD_IT_TO_YOUR_GLOBAL_OPTIONS="Get token from VDM to get update notice, and add it to your global options." COM_COMPONENTBUILDER_GIVE_TO_JCB="Give to JCB" COM_COMPONENTBUILDER_GLOBAL="Global" COM_COMPONENTBUILDER_GLUECODE="Glue/Code" +COM_COMPONENTBUILDER_GRAB_THE_LATEST_S_TESTING_RELEASE="Grab the latest %s testing release!" COM_COMPONENTBUILDER_GREAT_THIS_FUNCTION_NAME_WILL_WORK="Great, this function name will work!" COM_COMPONENTBUILDER_GREAT_THIS_PLACEHOLDER_WILL_WORK="Great, this placeholder will work!" COM_COMPONENTBUILDER_GREAT_THIS_VALIDATION_RULE_NAME_S_WILL_WORK="Great, this validation rule name (%s) will work!" @@ -5370,6 +5369,7 @@ COM_COMPONENTBUILDER_HELP_DOCUMENT_VERSION_DESC="A count of the number of times COM_COMPONENTBUILDER_HELP_DOCUMENT_VERSION_LABEL="Version" COM_COMPONENTBUILDER_HELP_JCB_GROW="Help JCB Grow" COM_COMPONENTBUILDER_HELP_MANAGER="Help" +COM_COMPONENTBUILDER_HELP_US_TEST_THE_UPCOMING_RELEASE="Help us test the upcoming release!" COM_COMPONENTBUILDER_HERE_YOU_CAN_ENTER_THE_REPLACE_TEXT_THAT_YOU_WOULD_LIKE_TO_USE_AS_REPLACEMENT_FOR_THE_SEARCH_TEXT_FOUND="Here you can enter the replace text that you would like to use as replacement for the search text found." COM_COMPONENTBUILDER_HERE_YOU_CAN_ENTER_YOUR_SEARCH_TEXT="Here you can enter your search text." COM_COMPONENTBUILDER_HERE_YOU_CAN_SET_THE_PATH_TO_THE_SUPER_POWERS_LOCAL_REPOSITORY_FOLDER_WHERE_BLAYERCOREB_AND_ALL_TARGETED_BLAYEROWNB_SUB_PATHS_WILL_BE_PLACED_WITH_THEIR_SELECTIVE_BSWITCHAPPROVEDB_POWERS="Here you can set the path to the super powers local repository folder, where [layer:core] and all targeted [layer:own] sub paths will be placed with their selective [switch:approved] powers." @@ -7630,7 +7630,6 @@ COM_COMPONENTBUILDER_NO_ADMIN_VIEWS_FOUND="No Admin Views Found" COM_COMPONENTBUILDER_NO_CHANGE_S_ITEM_S_IN_REPO_S_IS_ALREADY_IN_SYNC="NO CHANGE: %s item [%s] in repo (%s) is already in sync." COM_COMPONENTBUILDER_NO_COMPONENTS_FOUND="No Components Found" COM_COMPONENTBUILDER_NO_COMPONENT_DETAILS_FOUND_SO_IT_IS_NOT_SAFE_TO_CONTINUE="No component details found, so it is not safe to continue!" -COM_COMPONENTBUILDER_NO_CRONJOB_PATHS_WAS_REMOVED_WE_WILL_CHANGE_TO_WORKFLOWS_SOON="No cronjob paths was removed, we will change to workflows soon." COM_COMPONENTBUILDER_NO_DESCRIPTION_FOUND="No description found." COM_COMPONENTBUILDER_NO_FIELDS_WHERE_SELECTED="No fields where selected!" COM_COMPONENTBUILDER_NO_FILES_LINKED="No Files Linked" @@ -8035,7 +8034,7 @@ COM_COMPONENTBUILDER_REPOSITORIES_N_ITEMS_UNPUBLISHED_1="%s Repository unpublish COM_COMPONENTBUILDER_REPOSITORIES_SUBMENU="Repositories Submenu" COM_COMPONENTBUILDER_REPOSITORIES_SUBMENU_DESC="Allows the users in this group to submenu of repository" COM_COMPONENTBUILDER_REPOSITORY="Repository" -COM_COMPONENTBUILDER_REPOSITORY_ACCESS_REPO_DESCRIPTION="Set the access options to this repository. Global is only applicable to git.vdm.dev repos." +COM_COMPONENTBUILDER_REPOSITORY_ACCESS_REPO_DESCRIPTION="Set the access options to this repository. Global is only applicable to github.com and git.vdm.dev repos." COM_COMPONENTBUILDER_REPOSITORY_ACCESS_REPO_LABEL="Access" COM_COMPONENTBUILDER_REPOSITORY_ADDPLACEHOLDERS_DESCRIPTION="Set dnamic placeholders for this component." COM_COMPONENTBUILDER_REPOSITORY_ADDPLACEHOLDERS_LABEL="Placeholders" @@ -9144,6 +9143,7 @@ COM_COMPONENTBUILDER_TEMPLATE_TEMPLATE_LABEL="Template" COM_COMPONENTBUILDER_TEMPLATE_VERSION_DESC="A count of the number of times this Template has been revised." COM_COMPONENTBUILDER_TEMPLATE_VERSION_LABEL="Version" COM_COMPONENTBUILDER_TEMPLATE_YES="Yes" +COM_COMPONENTBUILDER_THANK_YOU_FOR_TESTING_THE_S_RELEASE_YOURE_A_JCB_HERO="Thank you for testing the %s release — you're a JCB hero!" COM_COMPONENTBUILDER_THERE_HAS_BEEN_AN_ERROR_IF_THIS_CONTINUES_PLEASE_INFORM_YOUR_SYSTEM_ADMINISTRATOR_OF_A_TYPE_ERROR_IN_THE_FIELDS_DISPLAY_REQUEST="There has been an error, if this continues please inform your system administrator of a type error in the fields display request!" COM_COMPONENTBUILDER_THERE_HAS_BEEN_AN_ERROR_PLEASE_TRY_AGAIN="There has been an error please try again" COM_COMPONENTBUILDER_THERE_WAS_AN_ERROR_GETTING_THE_PACKAGE_INFO="There was an error getting the package info." diff --git a/admin/sql/install.mysql.utf8.sql b/admin/sql/install.mysql.utf8.sql index 03572520b..f92a879d2 100644 --- a/admin/sql/install.mysql.utf8.sql +++ b/admin/sql/install.mysql.utf8.sql @@ -3022,8 +3022,8 @@ INSERT INTO `#__componentbuilder_repository` (`id`, `system_name`, `organisation (17, 'Openai (codeberg - mirror)', 'joomla', 'openai', 1, 1, 'https://codeberg.org', 'c625381a-7795-4b9f-8b4e-997c9291e3fc', 'master', 1, 17, 1, '2025-06-17 21:47:49', '2024-06-10 11:03:19', '', '{}'), (18, 'Joomla Powers (codeberg - mirror)', 'joomla', 'joomla-powers', 2, 1, 'https://codeberg.org', '8ac595d4-0b1d-4877-ba3e-2b815c1c7e3c', 'master', 1, 18, 1, '2025-06-17 21:47:22', '2024-07-08 14:07:31', '', '{}'), (19, 'Joomla Field Types (codeberg - mirror)', 'joomla', 'joomla-fieldtypes', 3, 1, 'https://codeberg.org', 'bf4a1d77-e3a4-4aa8-a07f-2b01872bf7e9', 'master', 1, 19, 1, '2025-06-17 21:48:25', '2024-08-23 16:21:35', '', '{}'), -(20, 'Official Packages', 'joomengine', 'packages', 4, 2, 'https://api.github.com', '562624ab-48bf-4979-9a14-6b10cf3635de', 'master', 1, 20, 1, '2025-06-18 10:39:24', '2025-05-31 08:47:01', '', '{}'), -(21, 'Official Snippets', 'joomengine', 'snippets', 5, 2, 'https://api.github.com', '70e85588-bc28-4459-9b29-858f68faae8f', 'master', 1, 21, 1, '2025-06-18 18:46:05', '2025-06-18 10:35:14', '', '{}'); +(20, 'Official Packages (github - mirror)', 'joomengine', 'packages', 4, 2, 'https://api.github.com', '562624ab-48bf-4979-9a14-6b10cf3635de', 'master', 1, 20, 1, '2025-06-23 16:46:09', '2025-05-31 08:47:01', '', '{}'), +(21, 'Official Packages (github - mirror)', 'joomengine', 'snippets', 5, 2, 'https://api.github.com', '70e85588-bc28-4459-9b29-858f68faae8f', 'master', 1, 21, 1, '2025-06-23 16:46:13', '2025-06-18 10:35:14', '', '{}'); -- -- Dumping data for table `#__componentbuilder_help_document` diff --git a/admin/src/Controller/AjaxController.php b/admin/src/Controller/AjaxController.php index b7df510fb..2b28a95e9 100644 --- a/admin/src/Controller/AjaxController.php +++ b/admin/src/Controller/AjaxController.php @@ -50,7 +50,6 @@ class AjaxController extends BaseController $this->app->setHeader('Access-Control-Allow-Origin', '*'); // load the tasks $this->registerTask('getComponentDetails', 'ajax'); - $this->registerTask('getCronPath', 'ajax'); $this->registerTask('getWiki', 'ajax'); $this->registerTask('getVersion', 'ajax'); $this->registerTask('getJCBpackageInfo', 'ajax'); @@ -168,55 +167,6 @@ class AjaxController extends BaseController } } break; - case 'getCronPath': - try - { - $getTypeValue = $jinput->get('getType', NULL, 'WORD'); - if($getTypeValue && $user->id != 0) - { - $ajaxModule = $this->getModel('ajax', 'Administrator'); - if ($ajaxModule) - { - $result = $ajaxModule->getCronPath($getTypeValue); - } - else - { - $result = ['error' => 'There was an error! [149]']; - } - } - else - { - $result = ['error' => 'There was an error! [149]']; - } - if($callback) - { - echo $callback . "(".json_encode($result).");"; - } - elseif($returnRaw) - { - echo json_encode($result); - } - else - { - echo "(".json_encode($result).");"; - } - } - catch(\Exception $e) - { - if($callback) - { - echo $callback."(".json_encode($e).");"; - } - elseif($returnRaw) - { - echo json_encode($e); - } - else - { - echo "(".json_encode($e).");"; - } - } - break; case 'getWiki': try { diff --git a/admin/src/Model/AjaxModel.php b/admin/src/Model/AjaxModel.php index 085af0229..553d4ea96 100644 --- a/admin/src/Model/AjaxModel.php +++ b/admin/src/Model/AjaxModel.php @@ -33,6 +33,8 @@ use VDM\Joomla\Utilities\JsonHelper; use VDM\Joomla\Utilities\StringHelper; use VDM\Joomla\Componentbuilder\Search\Factory as SearchFactory; use VDM\Joomla\Utilities\GuidHelper; +use VDM\Joomla\Componentbuilder\Remote\Version; +use VDM\Joomla\Github\Factory as GithubFactory; use VDM\Joomla\Utilities\ArrayHelper as UtilitiesArrayHelper; use VDM\Joomla\Utilities\GetHelper; use VDM\Joomla\Utilities\SessionHelper; @@ -276,172 +278,46 @@ class AjaxModel extends ListModel return implode("\n", $html); } - - /** - * Will be removed, since we will change to workflows soon :) - */ - public function getCronPath($type) - { - return ['error' => '' . Text::_('COM_COMPONENTBUILDER_NO_CRONJOB_PATHS_WAS_REMOVED_WE_WILL_CHANGE_TO_WORKFLOWS_SOON') . '']; - } /** - * get Current Version + * Get the current version notice. * - * @param string|null $message The error messages if any. + * Compares the installed version of the component with the latest available + * version from the repository tags and returns an appropriate message. * - * @return array The array of the notice or error message + * @param string|null $version Optional version to compare if manifest version not found. + * + * @return array The array with 'notice' or 'error' and optional 'github-error' / 'gitea-error'. * @since 2.3.0 + * @since 5.1.1 Improved with support for pre-releases and intelligent tag grouping. */ - public function getVersion($version = null) + public function getVersion(?string $version = null): array { - try - { - // get the repository tags - $tags = GiteaFactory::_('Gitea.Repository.Tags')->list('joomla', 'Component-Builder'); - } - catch (DomainException $e) - { - return $this->getTokenForVersion($e->getMessage()); - } - catch (InvalidArgumentException $e) - { - return $this->getTokenForVersion($e->getMessage()); - } - catch (Exception $e) - { - return $this->getTokenForVersion($e->getMessage()); - } - // do we have tags returned - if (isset($tags[0]) && isset($tags[0]->name)) - { - // get the local version - $manifest = ComponentbuilderHelper::manifest(); - $local_version = (string) $manifest->version; - $latest_version = '1.0.0'; - $download_link = "https://git.vdm.dev/api/v1/joomla/Component-Builder"; - - // Filter tags by major version matching the local version's major number - $major_version = explode('.', $local_version)[0]; - $filtered_tags = array_filter($tags, function($tag) use ($major_version) { - return strpos($tag->name, "v$major_version") === 0; - }); - - if (!empty($filtered_tags)) - { - // Sort versions to find the latest one - usort($filtered_tags, function($a, $b) { - return \version_compare($b->name, $a->name); - }); - - $latest_version = trim($filtered_tags[0]->name, 'vV'); - - // download link of the latest version - $download_link = $filtered_tags[0]->zipball_url; - } - - // now check if this version is out dated - if (\version_compare($local_version, $latest_version) === 0) - { - return ['notice' => ' ' . Text::_('COM_COMPONENTBUILDER_UP_TO_DATE') . '']; - } - else - { - // check if this is beta version - if (\version_compare($local_version, $latest_version) > 0) - { - return ['notice' => ' ' . Text::_('COM_COMPONENTBUILDER_PRE_RELEASE') . '']; - } - else - { - return ['notice' => ' ' . Text::_('COM_COMPONENTBUILDER_OUT_OF_DATE') . '! ' . Text::_('COM_COMPONENTBUILDER_DOWNLOAD_UPDATE') . '!']; - } - } - } - - return $this->getTokenForVersion(); + return (new Version( + 'joomengine', 'pkg-component-builder', + 'joomla', 'pkg-component-builder' + ))->get($version); } /** - * Instructions to get Token for version + * Get the content of a GitHub wiki page. * - * @param string|null $message The error messages if any. + * @param string $name The name of the wiki page (default: 'Home'). * - * @return array The array of the error message - * @since 2.3.0 - */ - protected function getTokenForVersion(?string $message = null): array - { - // the URL - $url = 'https://git.vdm.dev/user/settings/applications'; - - // create link - $a = ''; - $_a = ''; - - if ($message) - { - return ['error' => $a . $message . $a_ . Text::_('COM_COMPONENTBUILDER_GET_TOKEN') . $_a]; - } - - return ['error' => $a . Text::_('COM_COMPONENTBUILDER_GET_TOKEN_FROM_VDM_TO_GET_UPDATE_NOTICE_AND_ADD_IT_TO_YOUR_GLOBAL_OPTIONS') . $a_ . Text::_('COM_COMPONENTBUILDER_GET_TOKEN') . $_a]; - } - - /** - * get Wiki Page - * - * @param string|null $message The error messages if any. - * - * @return array The array of the page or error message + * @return array Associative array with 'page' or 'error' key. * @since 2.3.0 */ public function getWiki(string $name = 'Home'): array { - try - { - // get the gitea wiki page im markdown - $wiki = GiteaFactory::_('Gitea.Repository.Wiki')->get('joomla', 'Component-Builder', $name); + try { + $wiki = GithubFactory::_('Github.Repository.Wiki') + ->get('joomengine', 'Joomla-Component-Builder', $name); - // now render the page in HTML - $page = $wiki->content ?? null; - } - catch (\DomainException $e) - { - return $this->getTokenForWiki($e->getMessage()); - } - catch (\InvalidArgumentException $e) - { - return $this->getTokenForWiki($e->getMessage()); - } - catch (\Exception $e) - { - return $this->getTokenForWiki($e->getMessage()); - } - - // get the html - if (isset($page)) - { - return ['page' => $page]; - } - - return $this->getTokenForWiki(); - } - - /** - * Instructions to get Token for wiki - * - * @param string|null $message The error messages if any. - * - * @return array The array of the error message - * @since 2.3.0 - */ - protected function getTokenForWiki(?string $message = null): array - { - if ($message) - { - return ['error' => $message]; + if (!empty($wiki->content)) { + return ['page' => base64_decode($wiki->content)]; + } + } catch (\Throwable $e) { + return ['error' => $e->getMessage()]; } return ['error' => Text::_('COM_COMPONENTBUILDER_THE_WIKI_CAN_ONLY_BE_LOADED_WHEN_YOUR_JCB_SYSTEM_HAS_INTERNET_CONNECTION')]; diff --git a/admin/src/Model/ComponentbuilderModel.php b/admin/src/Model/ComponentbuilderModel.php index 38f007e0e..254d3b2be 100644 --- a/admin/src/Model/ComponentbuilderModel.php +++ b/admin/src/Model/ComponentbuilderModel.php @@ -38,6 +38,233 @@ use VDM\Joomla\Utilities\StringHelper; */ class ComponentbuilderModel extends ListModel { + /** + * Represents the current user object. + * + * @var User The user object representing the current user. + * @since 3.2.0 + */ + protected User $user; + + /** + * View groups of this component + * + * @var array + * @since 5.1.1 + */ + protected array $viewGroups = [ + 'main' => ['png.compiler', 'png.joomla_components', 'png.joomla_modules', 'png.joomla_plugins', 'png.powers', 'png.search', 'png.admin_views', 'png.custom_admin_views', 'png.site_views', 'png.template.add', 'png.templates', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.placeholders', 'png.libraries', 'png.snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_field', 'png.fieldtypes', 'png.fieldtypes.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_fieldtype', 'png.language_translations', 'png.languages', 'png.servers', 'png.repositories', 'png.help_documents'], + ]; + + /** + * View access array. + * + * @var array + * @since 5.1.1 + */ + protected array $viewAccess = [ + 'compiler.submenu' => 'compiler.submenu', + 'compiler.dashboard_list' => 'compiler.dashboard_list', + 'search.access' => 'search.access', + 'search.submenu' => 'search.submenu', + 'search.dashboard_list' => 'search.dashboard_list', + 'joomla_component.create' => 'joomla_component.create', + 'joomla_components.access' => 'joomla_component.access', + 'joomla_component.access' => 'joomla_component.access', + 'joomla_components.submenu' => 'joomla_component.submenu', + 'joomla_components.dashboard_list' => 'joomla_component.dashboard_list', + 'joomla_module.create' => 'joomla_module.create', + 'joomla_modules.access' => 'joomla_module.access', + 'joomla_module.access' => 'joomla_module.access', + 'joomla_modules.submenu' => 'joomla_module.submenu', + 'joomla_modules.dashboard_list' => 'joomla_module.dashboard_list', + 'joomla_plugin.create' => 'joomla_plugin.create', + 'joomla_plugins.access' => 'joomla_plugin.access', + 'joomla_plugin.access' => 'joomla_plugin.access', + 'joomla_plugins.submenu' => 'joomla_plugin.submenu', + 'joomla_plugins.dashboard_list' => 'joomla_plugin.dashboard_list', + 'joomla_power.create' => 'joomla_power.create', + 'joomla_powers.access' => 'joomla_power.access', + 'joomla_power.access' => 'joomla_power.access', + 'joomla_powers.submenu' => 'joomla_power.submenu', + 'power.create' => 'power.create', + 'powers.access' => 'power.access', + 'power.access' => 'power.access', + 'powers.submenu' => 'power.submenu', + 'powers.dashboard_list' => 'power.dashboard_list', + 'admin_view.create' => 'admin_view.create', + 'admin_views.access' => 'admin_view.access', + 'admin_view.access' => 'admin_view.access', + 'admin_views.submenu' => 'admin_view.submenu', + 'admin_views.dashboard_list' => 'admin_view.dashboard_list', + 'custom_admin_views.access' => 'custom_admin_view.access', + 'custom_admin_view.access' => 'custom_admin_view.access', + 'custom_admin_views.submenu' => 'custom_admin_view.submenu', + 'custom_admin_views.dashboard_list' => 'custom_admin_view.dashboard_list', + 'site_views.access' => 'site_view.access', + 'site_view.access' => 'site_view.access', + 'site_views.submenu' => 'site_view.submenu', + 'site_views.dashboard_list' => 'site_view.dashboard_list', + 'templates.access' => 'template.access', + 'template.access' => 'template.access', + 'templates.submenu' => 'template.submenu', + 'templates.dashboard_list' => 'template.dashboard_list', + 'template.dashboard_add' => 'template.dashboard_add', + 'layouts.access' => 'layout.access', + 'layout.access' => 'layout.access', + 'layouts.submenu' => 'layout.submenu', + 'layouts.dashboard_list' => 'layout.dashboard_list', + 'dynamic_get.create' => 'dynamic_get.create', + 'dynamic_gets.access' => 'dynamic_get.access', + 'dynamic_get.access' => 'dynamic_get.access', + 'dynamic_gets.submenu' => 'dynamic_get.submenu', + 'dynamic_gets.dashboard_list' => 'dynamic_get.dashboard_list', + 'dynamic_get.dashboard_add' => 'dynamic_get.dashboard_add', + 'custom_code.create' => 'custom_code.create', + 'custom_codes.access' => 'custom_code.access', + 'custom_code.access' => 'custom_code.access', + 'custom_codes.submenu' => 'custom_code.submenu', + 'custom_codes.dashboard_list' => 'custom_code.dashboard_list', + 'class_extends.create' => 'class_extends.create', + 'class_extendings.access' => 'class_extends.access', + 'class_extends.access' => 'class_extends.access', + 'class_property.create' => 'class_property.create', + 'class_properties.access' => 'class_property.access', + 'class_property.access' => 'class_property.access', + 'class_method.create' => 'class_method.create', + 'class_methods.access' => 'class_method.access', + 'class_method.access' => 'class_method.access', + 'placeholder.create' => 'placeholder.create', + 'placeholders.access' => 'placeholder.access', + 'placeholder.access' => 'placeholder.access', + 'placeholders.submenu' => 'placeholder.submenu', + 'placeholders.dashboard_list' => 'placeholder.dashboard_list', + 'library.create' => 'library.create', + 'libraries.access' => 'library.access', + 'library.access' => 'library.access', + 'libraries.submenu' => 'library.submenu', + 'libraries.dashboard_list' => 'library.dashboard_list', + 'snippets.access' => 'snippet.access', + 'snippet.access' => 'snippet.access', + 'snippets.submenu' => 'snippet.submenu', + 'snippets.dashboard_list' => 'snippet.dashboard_list', + 'validation_rule.create' => 'validation_rule.create', + 'validation_rules.access' => 'validation_rule.access', + 'validation_rule.access' => 'validation_rule.access', + 'validation_rules.submenu' => 'validation_rule.submenu', + 'validation_rules.dashboard_list' => 'validation_rule.dashboard_list', + 'field.create' => 'field.create', + 'fields.access' => 'field.access', + 'field.access' => 'field.access', + 'fields.submenu' => 'field.submenu', + 'fields.dashboard_list' => 'field.dashboard_list', + 'field.dashboard_add' => 'field.dashboard_add', + 'fieldtype.create' => 'fieldtype.create', + 'fieldtypes.access' => 'fieldtype.access', + 'fieldtype.access' => 'fieldtype.access', + 'fieldtypes.submenu' => 'fieldtype.submenu', + 'fieldtypes.dashboard_list' => 'fieldtype.dashboard_list', + 'language_translation.create' => 'language_translation.create', + 'language_translations.access' => 'language_translation.access', + 'language_translation.access' => 'language_translation.access', + 'language_translations.submenu' => 'language_translation.submenu', + 'language_translations.dashboard_list' => 'language_translation.dashboard_list', + 'language.create' => 'language.create', + 'languages.access' => 'language.access', + 'language.access' => 'language.access', + 'languages.submenu' => 'language.submenu', + 'languages.dashboard_list' => 'language.dashboard_list', + 'server.create' => 'server.create', + 'servers.access' => 'server.access', + 'server.access' => 'server.access', + 'servers.submenu' => 'server.submenu', + 'servers.dashboard_list' => 'server.dashboard_list', + 'repository.create' => 'repository.create', + 'repositories.access' => 'repository.access', + 'repository.access' => 'repository.access', + 'repositories.submenu' => 'repository.submenu', + 'repositories.dashboard_list' => 'repository.dashboard_list', + 'help_document.create' => 'help_document.create', + 'help_documents.access' => 'help_document.access', + 'help_document.access' => 'help_document.access', + 'help_documents.submenu' => 'help_document.submenu', + 'help_documents.dashboard_list' => 'help_document.dashboard_list', + 'admin_fields.create' => 'admin_fields.create', + 'admins_fields.access' => 'admin_fields.access', + 'admin_fields.access' => 'admin_fields.access', + 'admin_fields_conditions.create' => 'admin_fields_conditions.create', + 'admins_fields_conditions.access' => 'admin_fields_conditions.access', + 'admin_fields_conditions.access' => 'admin_fields_conditions.access', + 'admin_fields_relations.create' => 'admin_fields_relations.create', + 'admins_fields_relations.access' => 'admin_fields_relations.access', + 'admin_fields_relations.access' => 'admin_fields_relations.access', + 'admin_custom_tabs.create' => 'admin_custom_tabs.create', + 'admins_custom_tabs.access' => 'admin_custom_tabs.access', + 'admin_custom_tabs.access' => 'admin_custom_tabs.access', + 'component_admin_views.create' => 'component_admin_views.create', + 'components_admin_views.access' => 'component_admin_views.access', + 'component_admin_views.access' => 'component_admin_views.access', + 'component_site_views.create' => 'component_site_views.create', + 'components_site_views.access' => 'component_site_views.access', + 'component_site_views.access' => 'component_site_views.access', + 'component_custom_admin_views.create' => 'component_custom_admin_views.create', + 'components_custom_admin_views.access' => 'component_custom_admin_views.access', + 'component_custom_admin_views.access' => 'component_custom_admin_views.access', + 'component_updates.create' => 'component_updates.create', + 'components_updates.access' => 'component_updates.access', + 'component_updates.access' => 'component_updates.access', + 'component_mysql_tweaks.create' => 'component_mysql_tweaks.create', + 'components_mysql_tweaks.access' => 'component_mysql_tweaks.access', + 'component_mysql_tweaks.access' => 'component_mysql_tweaks.access', + 'component_custom_admin_menus.create' => 'component_custom_admin_menus.create', + 'components_custom_admin_menus.access' => 'component_custom_admin_menus.access', + 'component_custom_admin_menus.access' => 'component_custom_admin_menus.access', + 'component_router.create' => 'component_router.create', + 'components_routers.access' => 'component_router.access', + 'component_router.access' => 'component_router.access', + 'component_config.create' => 'component_config.create', + 'components_config.access' => 'component_config.access', + 'component_config.access' => 'component_config.access', + 'component_dashboard.create' => 'component_dashboard.create', + 'components_dashboard.access' => 'component_dashboard.access', + 'component_dashboard.access' => 'component_dashboard.access', + 'component_files_folders.create' => 'component_files_folders.create', + 'components_files_folders.access' => 'component_files_folders.access', + 'component_files_folders.access' => 'component_files_folders.access', + 'component_placeholders.create' => 'component_placeholders.create', + 'components_placeholders.access' => 'component_placeholders.access', + 'component_placeholders.access' => 'component_placeholders.access', + 'component_plugins.create' => 'component_plugins.create', + 'components_plugins.access' => 'component_plugins.access', + 'component_plugins.access' => 'component_plugins.access', + 'component_modules.create' => 'component_modules.create', + 'components_modules.access' => 'component_modules.access', + 'component_modules.access' => 'component_modules.access', + 'snippet_type.create' => 'snippet_type.create', + 'snippet_types.access' => 'snippet_type.access', + 'snippet_type.access' => 'snippet_type.access', + 'library_config.create' => 'library_config.create', + 'libraries_config.access' => 'library_config.access', + 'library_config.access' => 'library_config.access', + 'library_files_folders_urls.create' => 'library_files_folders_urls.create', + 'libraries_files_folders_urls.access' => 'library_files_folders_urls.access', + 'library_files_folders_urls.access' => 'library_files_folders_urls.access', + 'joomla_module_updates.create' => 'joomla_module_updates.create', + 'joomla_modules_updates.access' => 'joomla_module_updates.access', + 'joomla_module_updates.access' => 'joomla_module_updates.access', + 'joomla_module_files_folders_urls.create' => 'joomla_module_files_folders_urls.create', + 'joomla_modules_files_folders_urls.access' => 'joomla_module_files_folders_urls.access', + 'joomla_module_files_folders_urls.access' => 'joomla_module_files_folders_urls.access', + 'joomla_plugin_groups.access' => 'joomla_plugin_group.access', + 'joomla_plugin_group.access' => 'joomla_plugin_group.access', + 'joomla_plugin_updates.create' => 'joomla_plugin_updates.create', + 'joomla_plugins_updates.access' => 'joomla_plugin_updates.access', + 'joomla_plugin_updates.access' => 'joomla_plugin_updates.access', + 'joomla_plugin_files_folders_urls.create' => 'joomla_plugin_files_folders_urls.create', + 'joomla_plugins_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access', + 'joomla_plugin_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access', + ]; + /** * The styles array. * @@ -59,402 +286,50 @@ class ComponentbuilderModel extends ListModel 'administrator/components/com_componentbuilder/assets/js/admin.js' ]; - public function getIcons() + /** + * Constructor + * + * @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request). + * @param ?MVCFactoryInterface $factory The factory. + * + * @since 1.6 + * @throws \Exception + */ + public function __construct($config = [], MVCFactoryInterface $factory = null) { - // load user for access menus - $user = Factory::getApplication()->getIdentity(); - // reset icon array - $icons = []; - // view groups array - $viewGroups = array( - 'main' => array('png.compiler', 'png.joomla_components', 'png.joomla_modules', 'png.joomla_plugins', 'png.powers', 'png.search', 'png.admin_views', 'png.custom_admin_views', 'png.site_views', 'png.template.add', 'png.templates', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.placeholders', 'png.libraries', 'png.snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_field', 'png.fieldtypes', 'png.fieldtypes.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_fieldtype', 'png.language_translations', 'png.languages', 'png.servers', 'png.repositories', 'png.help_documents') - ); - // view access array - $viewAccess = [ - 'compiler.submenu' => 'compiler.submenu', - 'compiler.dashboard_list' => 'compiler.dashboard_list', - 'search.access' => 'search.access', - 'search.submenu' => 'search.submenu', - 'search.dashboard_list' => 'search.dashboard_list', - 'joomla_component.create' => 'joomla_component.create', - 'joomla_components.access' => 'joomla_component.access', - 'joomla_component.access' => 'joomla_component.access', - 'joomla_components.submenu' => 'joomla_component.submenu', - 'joomla_components.dashboard_list' => 'joomla_component.dashboard_list', - 'joomla_module.create' => 'joomla_module.create', - 'joomla_modules.access' => 'joomla_module.access', - 'joomla_module.access' => 'joomla_module.access', - 'joomla_modules.submenu' => 'joomla_module.submenu', - 'joomla_modules.dashboard_list' => 'joomla_module.dashboard_list', - 'joomla_plugin.create' => 'joomla_plugin.create', - 'joomla_plugins.access' => 'joomla_plugin.access', - 'joomla_plugin.access' => 'joomla_plugin.access', - 'joomla_plugins.submenu' => 'joomla_plugin.submenu', - 'joomla_plugins.dashboard_list' => 'joomla_plugin.dashboard_list', - 'joomla_power.create' => 'joomla_power.create', - 'joomla_powers.access' => 'joomla_power.access', - 'joomla_power.access' => 'joomla_power.access', - 'joomla_powers.submenu' => 'joomla_power.submenu', - 'power.create' => 'power.create', - 'powers.access' => 'power.access', - 'power.access' => 'power.access', - 'powers.submenu' => 'power.submenu', - 'powers.dashboard_list' => 'power.dashboard_list', - 'admin_view.create' => 'admin_view.create', - 'admin_views.access' => 'admin_view.access', - 'admin_view.access' => 'admin_view.access', - 'admin_views.submenu' => 'admin_view.submenu', - 'admin_views.dashboard_list' => 'admin_view.dashboard_list', - 'custom_admin_views.access' => 'custom_admin_view.access', - 'custom_admin_view.access' => 'custom_admin_view.access', - 'custom_admin_views.submenu' => 'custom_admin_view.submenu', - 'custom_admin_views.dashboard_list' => 'custom_admin_view.dashboard_list', - 'site_views.access' => 'site_view.access', - 'site_view.access' => 'site_view.access', - 'site_views.submenu' => 'site_view.submenu', - 'site_views.dashboard_list' => 'site_view.dashboard_list', - 'templates.access' => 'template.access', - 'template.access' => 'template.access', - 'templates.submenu' => 'template.submenu', - 'templates.dashboard_list' => 'template.dashboard_list', - 'template.dashboard_add' => 'template.dashboard_add', - 'layouts.access' => 'layout.access', - 'layout.access' => 'layout.access', - 'layouts.submenu' => 'layout.submenu', - 'layouts.dashboard_list' => 'layout.dashboard_list', - 'dynamic_get.create' => 'dynamic_get.create', - 'dynamic_gets.access' => 'dynamic_get.access', - 'dynamic_get.access' => 'dynamic_get.access', - 'dynamic_gets.submenu' => 'dynamic_get.submenu', - 'dynamic_gets.dashboard_list' => 'dynamic_get.dashboard_list', - 'dynamic_get.dashboard_add' => 'dynamic_get.dashboard_add', - 'custom_code.create' => 'custom_code.create', - 'custom_codes.access' => 'custom_code.access', - 'custom_code.access' => 'custom_code.access', - 'custom_codes.submenu' => 'custom_code.submenu', - 'custom_codes.dashboard_list' => 'custom_code.dashboard_list', - 'class_extends.create' => 'class_extends.create', - 'class_extendings.access' => 'class_extends.access', - 'class_extends.access' => 'class_extends.access', - 'class_property.create' => 'class_property.create', - 'class_properties.access' => 'class_property.access', - 'class_property.access' => 'class_property.access', - 'class_method.create' => 'class_method.create', - 'class_methods.access' => 'class_method.access', - 'class_method.access' => 'class_method.access', - 'placeholder.create' => 'placeholder.create', - 'placeholders.access' => 'placeholder.access', - 'placeholder.access' => 'placeholder.access', - 'placeholders.submenu' => 'placeholder.submenu', - 'placeholders.dashboard_list' => 'placeholder.dashboard_list', - 'library.create' => 'library.create', - 'libraries.access' => 'library.access', - 'library.access' => 'library.access', - 'libraries.submenu' => 'library.submenu', - 'libraries.dashboard_list' => 'library.dashboard_list', - 'snippets.access' => 'snippet.access', - 'snippet.access' => 'snippet.access', - 'snippets.submenu' => 'snippet.submenu', - 'snippets.dashboard_list' => 'snippet.dashboard_list', - 'validation_rule.create' => 'validation_rule.create', - 'validation_rules.access' => 'validation_rule.access', - 'validation_rule.access' => 'validation_rule.access', - 'validation_rules.submenu' => 'validation_rule.submenu', - 'validation_rules.dashboard_list' => 'validation_rule.dashboard_list', - 'field.create' => 'field.create', - 'fields.access' => 'field.access', - 'field.access' => 'field.access', - 'fields.submenu' => 'field.submenu', - 'fields.dashboard_list' => 'field.dashboard_list', - 'field.dashboard_add' => 'field.dashboard_add', - 'fieldtype.create' => 'fieldtype.create', - 'fieldtypes.access' => 'fieldtype.access', - 'fieldtype.access' => 'fieldtype.access', - 'fieldtypes.submenu' => 'fieldtype.submenu', - 'fieldtypes.dashboard_list' => 'fieldtype.dashboard_list', - 'language_translation.create' => 'language_translation.create', - 'language_translations.access' => 'language_translation.access', - 'language_translation.access' => 'language_translation.access', - 'language_translations.submenu' => 'language_translation.submenu', - 'language_translations.dashboard_list' => 'language_translation.dashboard_list', - 'language.create' => 'language.create', - 'languages.access' => 'language.access', - 'language.access' => 'language.access', - 'languages.submenu' => 'language.submenu', - 'languages.dashboard_list' => 'language.dashboard_list', - 'server.create' => 'server.create', - 'servers.access' => 'server.access', - 'server.access' => 'server.access', - 'servers.submenu' => 'server.submenu', - 'servers.dashboard_list' => 'server.dashboard_list', - 'repository.create' => 'repository.create', - 'repositories.access' => 'repository.access', - 'repository.access' => 'repository.access', - 'repositories.submenu' => 'repository.submenu', - 'repositories.dashboard_list' => 'repository.dashboard_list', - 'help_document.create' => 'help_document.create', - 'help_documents.access' => 'help_document.access', - 'help_document.access' => 'help_document.access', - 'help_documents.submenu' => 'help_document.submenu', - 'help_documents.dashboard_list' => 'help_document.dashboard_list', - 'admin_fields.create' => 'admin_fields.create', - 'admins_fields.access' => 'admin_fields.access', - 'admin_fields.access' => 'admin_fields.access', - 'admin_fields_conditions.create' => 'admin_fields_conditions.create', - 'admins_fields_conditions.access' => 'admin_fields_conditions.access', - 'admin_fields_conditions.access' => 'admin_fields_conditions.access', - 'admin_fields_relations.create' => 'admin_fields_relations.create', - 'admins_fields_relations.access' => 'admin_fields_relations.access', - 'admin_fields_relations.access' => 'admin_fields_relations.access', - 'admin_custom_tabs.create' => 'admin_custom_tabs.create', - 'admins_custom_tabs.access' => 'admin_custom_tabs.access', - 'admin_custom_tabs.access' => 'admin_custom_tabs.access', - 'component_admin_views.create' => 'component_admin_views.create', - 'components_admin_views.access' => 'component_admin_views.access', - 'component_admin_views.access' => 'component_admin_views.access', - 'component_site_views.create' => 'component_site_views.create', - 'components_site_views.access' => 'component_site_views.access', - 'component_site_views.access' => 'component_site_views.access', - 'component_custom_admin_views.create' => 'component_custom_admin_views.create', - 'components_custom_admin_views.access' => 'component_custom_admin_views.access', - 'component_custom_admin_views.access' => 'component_custom_admin_views.access', - 'component_updates.create' => 'component_updates.create', - 'components_updates.access' => 'component_updates.access', - 'component_updates.access' => 'component_updates.access', - 'component_mysql_tweaks.create' => 'component_mysql_tweaks.create', - 'components_mysql_tweaks.access' => 'component_mysql_tweaks.access', - 'component_mysql_tweaks.access' => 'component_mysql_tweaks.access', - 'component_custom_admin_menus.create' => 'component_custom_admin_menus.create', - 'components_custom_admin_menus.access' => 'component_custom_admin_menus.access', - 'component_custom_admin_menus.access' => 'component_custom_admin_menus.access', - 'component_router.create' => 'component_router.create', - 'components_routers.access' => 'component_router.access', - 'component_router.access' => 'component_router.access', - 'component_config.create' => 'component_config.create', - 'components_config.access' => 'component_config.access', - 'component_config.access' => 'component_config.access', - 'component_dashboard.create' => 'component_dashboard.create', - 'components_dashboard.access' => 'component_dashboard.access', - 'component_dashboard.access' => 'component_dashboard.access', - 'component_files_folders.create' => 'component_files_folders.create', - 'components_files_folders.access' => 'component_files_folders.access', - 'component_files_folders.access' => 'component_files_folders.access', - 'component_placeholders.create' => 'component_placeholders.create', - 'components_placeholders.access' => 'component_placeholders.access', - 'component_placeholders.access' => 'component_placeholders.access', - 'component_plugins.create' => 'component_plugins.create', - 'components_plugins.access' => 'component_plugins.access', - 'component_plugins.access' => 'component_plugins.access', - 'component_modules.create' => 'component_modules.create', - 'components_modules.access' => 'component_modules.access', - 'component_modules.access' => 'component_modules.access', - 'snippet_type.create' => 'snippet_type.create', - 'snippet_types.access' => 'snippet_type.access', - 'snippet_type.access' => 'snippet_type.access', - 'library_config.create' => 'library_config.create', - 'libraries_config.access' => 'library_config.access', - 'library_config.access' => 'library_config.access', - 'library_files_folders_urls.create' => 'library_files_folders_urls.create', - 'libraries_files_folders_urls.access' => 'library_files_folders_urls.access', - 'library_files_folders_urls.access' => 'library_files_folders_urls.access', - 'joomla_module_updates.create' => 'joomla_module_updates.create', - 'joomla_modules_updates.access' => 'joomla_module_updates.access', - 'joomla_module_updates.access' => 'joomla_module_updates.access', - 'joomla_module_files_folders_urls.create' => 'joomla_module_files_folders_urls.create', - 'joomla_modules_files_folders_urls.access' => 'joomla_module_files_folders_urls.access', - 'joomla_module_files_folders_urls.access' => 'joomla_module_files_folders_urls.access', - 'joomla_plugin_groups.access' => 'joomla_plugin_group.access', - 'joomla_plugin_group.access' => 'joomla_plugin_group.access', - 'joomla_plugin_updates.create' => 'joomla_plugin_updates.create', - 'joomla_plugins_updates.access' => 'joomla_plugin_updates.access', - 'joomla_plugin_updates.access' => 'joomla_plugin_updates.access', - 'joomla_plugin_files_folders_urls.create' => 'joomla_plugin_files_folders_urls.create', - 'joomla_plugins_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access', - 'joomla_plugin_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access', - ]; - // loop over the $views - foreach($viewGroups as $group => $views) + parent::__construct($config, $factory); + + $this->user ??= $this->getCurrentUser(); + } + + /** + * Get dashboard icons, grouped by view sections. + * + * @return array> + * @since 5.1.1 + */ + public function getIcons(): array + { + $icons = []; + + foreach ($this->viewGroups as $group => $views) { - $i = 0; - if (UtilitiesArrayHelper::check($views)) + if (!UtilitiesArrayHelper::check($views)) { - foreach($views as $view) + $icons[$group][] = false; + continue; + } + + foreach ($views as $view) + { + $icon = $this->buildIconObject($view); + if ($icon !== null) { - $add = false; - // external views (links) - if (strpos($view,'||') !== false) - { - $dwd = explode('||', $view); - if (count($dwd) == 3) - { - list($type, $name, $url) = $dwd; - $viewName = $name; - $alt = $name; - $url = $url; - $image = $name . '.' . $type; - $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U'); - } - } - // internal views - elseif (strpos($view,'.') !== false) - { - $dwd = explode('.', $view); - if (count($dwd) == 3) - { - list($type, $name, $action) = $dwd; - } - elseif (count($dwd) == 2) - { - list($type, $name) = $dwd; - $action = false; - } - if ($action) - { - $viewName = $name; - switch($action) - { - case 'add': - $url = 'index.php?option=com_componentbuilder&view=' . $name . '&layout=edit'; - $image = $name . '_' . $action. '.' . $type; - $alt = $name . ' ' . $action; - $name = 'COM_COMPONENTBUILDER_DASHBOARD_'.StringHelper::safe($name,'U').'_ADD'; - $add = true; - break; - default: - // check for new convention (more stable) - if (strpos($action, '_qpo0O0oqp_') !== false) - { - list($action, $extension) = (array) explode('_qpo0O0oqp_', $action); - $extension = str_replace('_po0O0oq_', '.', $extension); - } - else - { - $extension = 'com_componentbuilder.' . $name; - } - $url = 'index.php?option=com_categories&view=categories&extension=' . $extension; - $image = $name . '_' . $action . '.' . $type; - $alt = $viewName . ' ' . $action; - $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U') . '_' . StringHelper::safe($action,'U'); - break; - } - } - else - { - $viewName = $name; - $alt = $name; - $url = 'index.php?option=com_componentbuilder&view=' . $name; - $image = $name . '.' . $type; - $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U'); - $hover = false; - } - } - else - { - $viewName = $view; - $alt = $view; - $url = 'index.php?option=com_componentbuilder&view=' . $view; - $image = $view . '.png'; - $name = ucwords($view).'

'; - $hover = false; - } - // first make sure the view access is set - if (UtilitiesArrayHelper::check($viewAccess)) - { - // setup some defaults - $dashboard_add = false; - $dashboard_list = false; - $accessTo = ''; - $accessAdd = ''; - // access checking start - $accessCreate = (isset($viewAccess[$viewName.'.create'])) ? StringHelper::check($viewAccess[$viewName.'.create']):false; - $accessAccess = (isset($viewAccess[$viewName.'.access'])) ? StringHelper::check($viewAccess[$viewName.'.access']):false; - // set main controllers - $accessDashboard_add = (isset($viewAccess[$viewName.'.dashboard_add'])) ? StringHelper::check($viewAccess[$viewName.'.dashboard_add']):false; - $accessDashboard_list = (isset($viewAccess[$viewName.'.dashboard_list'])) ? StringHelper::check($viewAccess[$viewName.'.dashboard_list']):false; - // check for adding access - if ($add && $accessCreate) - { - $accessAdd = $viewAccess[$viewName.'.create']; - } - elseif ($add) - { - $accessAdd = 'core.create'; - } - // check if access to view is set - if ($accessAccess) - { - $accessTo = $viewAccess[$viewName.'.access']; - } - // set main access controllers - if ($accessDashboard_add) - { - $dashboard_add = $user->authorise($viewAccess[$viewName.'.dashboard_add'], 'com_componentbuilder'); - } - if ($accessDashboard_list) - { - $dashboard_list = $user->authorise($viewAccess[$viewName.'.dashboard_list'], 'com_componentbuilder'); - } - if (StringHelper::check($accessAdd) && StringHelper::check($accessTo)) - { - // check access - if($user->authorise($accessAdd, 'com_componentbuilder') && $user->authorise($accessTo, 'com_componentbuilder') && $dashboard_add) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - elseif (StringHelper::check($accessTo)) - { - // check access - if($user->authorise($accessTo, 'com_componentbuilder') && $dashboard_list) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - elseif (StringHelper::check($accessAdd)) - { - // check access - if($user->authorise($accessAdd, 'com_componentbuilder') && $dashboard_add) - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - else - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - } - else - { - $icons[$group][$i] = new \StdClass; - $icons[$group][$i]->url = $url; - $icons[$group][$i]->name = $name; - $icons[$group][$i]->image = $image; - $icons[$group][$i]->alt = $alt; - } - $i++; + $icons[$group][] = $icon; } } - else - { - $icons[$group][$i] = false; - } } + return $icons; } @@ -502,13 +377,208 @@ class ComponentbuilderModel extends ListModel $this->scripts[] = $path; } + /** + * Build a single dashboard icon if access is granted. + * + * @param string $view The view string to parse. + * + * @return \stdClass|null The icon object or null if access denied. + * @since 5.1.1 + */ + protected function buildIconObject(string $view): ?\stdClass + { + $parsed = $this->parseViewDefinition($view); + if (!$parsed) + { + return null; + } + [ + 'type' => $type, + 'name' => $name, + 'url' => $url, + 'image' => $image, + 'alt' => $alt, + 'viewName' => $viewName, + 'add' => $add, + ] = $parsed; + + if (!$this->hasAccessToView($viewName, $add)) + { + return null; + } + + return $this->createIconObject($url, $name, $image, $alt); + } + + /** + * Parse a view string into structured components. + * + * @param string $view The view definition string. + * + * @return array|null Parsed values or null on failure. + * @since 5.1.1 + */ + protected function parseViewDefinition(string $view): ?array + { + $add = false; + + if (strpos($view, '||') !== false) + { + $parts = explode('||', $view); + if (count($parts) === 3) + { + [$type, $name, $url] = $parts; + return [ + 'type' => $type, + 'name' => 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name, 'U'), + 'url' => $url, + 'image' => "{$name}.{$type}", + 'alt' => $name, + 'viewName' => $name, + 'add' => false, + ]; + } + } + + if (strpos($view, '.') !== false) + { + $parts = explode('.', $view); + $type = $parts[0] ?? ''; + $name = $parts[1] ?? ''; + $action = $parts[2] ?? null; + $viewName = $name; + + if ($action) + { + if ($action === 'add') + { + $url = "index.php?option=com_componentbuilder&view={$name}&layout=edit"; + $image = "{$name}_{$action}.{$type}"; + $alt = "{$name} {$action}"; + $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . + StringHelper::safe($name, 'U') . '_ADD'; + $add = true; + } + else + { + if (strpos($action, '_qpo0O0oqp_') !== false) + { + [$action, $ext] = explode('_qpo0O0oqp_', $action); + $extension = str_replace('_po0O0oq_', '.', $ext); + } + else + { + $extension = "com_componentbuilder.{$name}"; + } + $url = "index.php?option=com_categories&view=categories&extension={$extension}"; + $image = "{$name}_{$action}.{$type}"; + $alt = "{$name} {$action}"; + $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . + StringHelper::safe($name, 'U') . '_' . + StringHelper::safe($action, 'U'); + } + } + else + { + $url = "index.php?option=com_componentbuilder&view={$name}"; + $image = "{$name}.{$type}"; + $alt = $name; + $name = 'COM_COMPONENTBUILDER_DASHBOARD_' . + StringHelper::safe($name, 'U'); + } + + return compact('type', 'name', 'url', 'image', 'alt', 'viewName', 'add'); + } + + return [ + 'type' => 'png', + 'name' => ucwords($view) . '

', + 'url' => "index.php?option=com_componentbuilder&view={$view}", + 'image' => "{$view}.png", + 'alt' => $view, + 'viewName' => $view, + 'add' => false, + ]; + } + + /** + * Determine if the user has access to view or create the item. + * + * @param string $viewName The base name of the view. + * @param bool $add If this is an add-action. + * + * @return bool + * @since 5.1.1 + */ + protected function hasAccessToView(string $viewName, bool $add): bool + { + $viewAccess = $this->viewAccess; + $accessAdd = $add && isset($viewAccess["{$viewName}.create"]) + ? $viewAccess["{$viewName}.create"] + : ($add ? 'core.create' : ''); + + $accessTo = $viewAccess["{$viewName}.access"] ?? ''; + + $dashboardAdd = isset($viewAccess["{$viewName}.dashboard_add"]) && + $this->user->authorise($viewAccess["{$viewName}.dashboard_add"], 'com_componentbuilder'); + + $dashboardList = isset($viewAccess["{$viewName}.dashboard_list"]) && + $this->user->authorise($viewAccess["{$viewName}.dashboard_list"], 'com_componentbuilder'); + + if ($add && StringHelper::check($accessAdd)) + { + return $this->user->authorise($accessAdd, 'com_componentbuilder') && $dashboardAdd; + } + + if (StringHelper::check($accessTo)) + { + return $this->user->authorise($accessTo, 'com_componentbuilder') && $dashboardList; + } + + return !$accessTo && !$accessAdd; + } + + /** + * Create a \stdClass icon object. + * + * @param string $url Icon URL. + * @param string $name Language string or label. + * @param string $image Image filename. + * @param string $alt Alt text. + * + * @return \stdClass + * @since 5.1.1 + */ + protected function createIconObject(string $url, string $name, string $image, string $alt): \stdClass + { + $icon = new \stdClass; + $icon->url = $url; + $icon->name = $name; + $icon->image = $image; + $icon->alt = $alt; + return $icon; + } + + + /** + * Load and display the wiki page content using an AJAX call to the component endpoint. + * + * This method injects an inline JavaScript script that asynchronously fetches the wiki page content + * via a JSON API endpoint in the component. It uses the `marked` library to render markdown content + * and inserts the result into the `wiki-md` container. Errors are displayed in a separate element. + * + * @return string HTML markup including a container for the wiki content and an error message area. + * @since 3.9.0 + */ public function getWiki() { - // the call URL + // call the ajax get wiki endpoint $call_url = Uri::base() . 'index.php?option=com_componentbuilder&task=ajax.getWiki&format=json&raw=true&' . Session::getFormToken() . '=1&name=Home'; - $document = Factory::getDocument(); - $document->addScriptDeclaration(' + + /** \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); + $wa->addInlineScript(' function getWikiPage(){ fetch("' . $call_url . '").then((response) => { if (response.ok) { @@ -528,13 +598,27 @@ class ComponentbuilderModel extends ListModel } + /** + * Load and display the component's README file using JavaScript fetch and markdown rendering. + * + * This method injects an inline script into the document that, once the DOM is fully loaded, + * fetches the README.txt file located in the administrator component directory, parses it using + * the `marked` JavaScript library, and inserts the HTML into the `readme-md` div. + * + * @return string HTML markup including a container for the README content and a loading message. + * @since 3.9.0 + */ public function getReadme() { - $document = Factory::getDocument(); - $document->addScriptDeclaration(' - var getreadme = "'. Uri::root() . 'administrator/components/com_componentbuilder/README.txt"; + // get readme text path + $call_url = Uri::root() . 'administrator/components/com_componentbuilder/README.txt'; + + /** \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); + + $wa->addInlineScript(' document.addEventListener("DOMContentLoaded", function () { - fetch(getreadme) + fetch("'. $call_url . '") .then(response => { if (!response.ok) { throw new Error("Network response was not ok"); @@ -554,31 +638,45 @@ class ComponentbuilderModel extends ListModel } /** - * get Current Version Bay adding JavaScript to the Page + * Inject JavaScript that fetches and displays the current component version status. * - * @return void - * @since 2.3.0 + * This method adds an inline script to the page which asynchronously calls the component's + * AJAX endpoint to check the latest version. It updates the `#component-update-notice` element + * with the fetched version notice or error message. + * + * @return void + * @since 2.3.0 */ public function getVersion() { - // the call URL - $call_url = Uri::base() . 'index.php?option=com_componentbuilder&task=ajax.getVersion&format=json&raw=true&' . Session::getFormToken() . '=1&version=1'; - $document = Factory::getDocument(); - $document->addScriptDeclaration(' - function getComponentVersionStatus() { - fetch("' . $call_url . '").then((response) => { - if (response.ok) { - return response.json(); - } - }).then((result) => { - if (typeof result.notice !== "undefined") { - document.getElementById("component-update-notice").innerHTML = result.notice; - } else if (typeof result.error !== "undefined") { - document.getElementById("component-update-notice").innerHTML = result.error; - } - }); + // call the ajax get version endpoint + $call_url = Uri::base() + . 'index.php?option=com_componentbuilder&task=ajax.getVersion&format=json&raw=true&' + . Session::getFormToken() . '=1&version=1.0.0'; + + try { + /** \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); + + $wa->addInlineScript(' + function getComponentVersionStatus() { + fetch("' . $call_url . '").then((response) => { + if (response.ok) { + return response.json(); + } + }).then((result) => { + const target = document.getElementById("component-update-notice"); + if (!target) return; + if (typeof result.notice !== "undefined") { + target.innerHTML = result.notice; + } else if (typeof result.error !== "undefined") { + target.innerHTML = result.error; + } + }); + } + setTimeout(getComponentVersionStatus, 800);'); + } catch (\Throwable $e) { + // we do nothing.... } - setTimeout(getComponentVersionStatus, 800);'); - } - + } } diff --git a/admin/src/View/Componentbuilder/HtmlView.php b/admin/src/View/Componentbuilder/HtmlView.php index cb2731c2a..9c1cbaa6a 100644 --- a/admin/src/View/Componentbuilder/HtmlView.php +++ b/admin/src/View/Componentbuilder/HtmlView.php @@ -30,6 +30,60 @@ use VDM\Joomla\Utilities\StringHelper; #[\AllowDynamicProperties] class HtmlView extends BaseHtmlView { + /** + * @var array List of icon identifiers to render in the dashboard view. + * @since 1.6 + */ + public array $icons = []; + + /** + * @var array List of CSS file URLs to be added to the page. + * @since 4.3 + */ + public array $styles = []; + + /** + * @var array List of JavaScript file URLs to be included on the page. + * @since 4.3 + */ + public array $scripts = []; + + /** + * @var array List of contributor objects fetched via the helper. + * @since 1.6 + */ + public array $contributors = []; + + /** + * @var object|null The manifest metadata of the component as returned by `ComponentbuilderHelper::manifest()`. + * @since 1.6 + */ + public $manifest = null; + + /** + * @var string|null Markdown content of the component's wiki page. + * @since 1.6 + */ + public ?string $wiki = null; + + /** + * @var string|null The rendered or raw README markdown of the component. + * @since 1.6 + */ + public ?string $readme = null; + + /** + * @var string|null The current version of the component. + * @since 1.6 + */ + public ?string $version = null; + + /** + * @var string|null Help URL for the component dashboard view, if available. + * @since 1.6 + */ + public ?string $help_url = null; + /** * View display method * @@ -101,8 +155,12 @@ class HtmlView extends BaseHtmlView { // set page title $this->getDocument()->setTitle(Text::_('COM_COMPONENTBUILDER_DASHBOARD')); - // add manifest to page JavaScript - $this->getDocument()->addScriptDeclaration("var manifest = JSON.parse(" . json_encode($this->manifest) . ");", "text/javascript"); + /** \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->getDocument()->getWebAssetManager(); + // Register the inline script with properly encoded JSON + $wa->addInlineScript( + 'var manifest = ' . json_encode($this->manifest, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ';' + ); // add styles foreach ($this->styles as $style) { diff --git a/componentbuilder.xml b/componentbuilder.xml index f67177b21..2714ee924 100644 --- a/componentbuilder.xml +++ b/componentbuilder.xml @@ -1,15 +1,15 @@ COM_COMPONENTBUILDER - 19th June, 2025 + 23rd June, 2025 Llewellyn van der Merwe joomla@vdm.io https://dev.vdm.io Copyright (C) 2015 Vast Development Method. All rights reserved. GNU General Public License version 2 or later; see LICENSE.txt - 5.1.1-beta2 + 5.1.1-beta3 Component Builder (v.5.1.1-beta2) +

Component Builder (v.5.1.1-beta3)

The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time. diff --git a/componentbuilder_update_server.xml b/componentbuilder_update_server.xml index 1d8afd621..9f2e3a088 100644 --- a/componentbuilder_update_server.xml +++ b/componentbuilder_update_server.xml @@ -134,14 +134,14 @@ 5.1.1-beta https://dev.vdm.io - https://github.com/vdm-io/pkg-component-builder/archive/refs/tags/v5.1.1-beta2.zip + https://github.com/vdm-io/pkg-component-builder/archive/refs/tags/v5.1.1-beta3.zip beta Llewellyn van der Merwe https://dev.vdm.io - + Component Builder @@ -149,16 +149,16 @@ pkg_component_builder package site - 5.1.1-beta2 + 5.1.1-beta3 https://dev.vdm.io - https://github.com/vdm-io/pkg-component-builder/archive/refs/tags/v5.1.1-beta2.zip + https://github.com/vdm-io/pkg-component-builder/archive/refs/tags/v5.1.1-beta3.zip beta Llewellyn van der Merwe https://dev.vdm.io - + \ No newline at end of file diff --git a/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Tags.php b/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Tags.php index 600bfc2b0..f2967178c 100644 --- a/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Tags.php +++ b/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Tags.php @@ -12,6 +12,7 @@ namespace VDM\Joomla\Gitea\Repository; +use VDM\Joomla\Interfaces\Git\Repository\TagsInterface; use VDM\Joomla\Gitea\Abstraction\Api; @@ -20,7 +21,7 @@ use VDM\Joomla\Gitea\Abstraction\Api; * * @since 3.2.0 */ -class Tags extends Api +class Tags extends Api implements TagsInterface { /** * List a repository's tags diff --git a/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Wiki.php b/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Wiki.php index 748860817..1a80320a4 100644 --- a/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Wiki.php +++ b/libraries/vendor_jcb/VDM.Joomla.Gitea/src/Repository/Wiki.php @@ -12,6 +12,7 @@ namespace VDM\Joomla\Gitea\Repository; +use VDM\Joomla\Interfaces\Git\Repository\WikiInterface; use VDM\Joomla\Gitea\Abstraction\Api; @@ -20,16 +21,16 @@ use VDM\Joomla\Gitea\Abstraction\Api; * * @since 3.2.0 */ -class Wiki extends Api +class Wiki extends Api implements WikiInterface { /** * Create a wiki page. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param string $title The title of the wiki page. - * @param string $contentBase64 The base64 encoded content of the wiki page. - * @param string|null $message Optional commit message summarizing the change. + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $title The title of the wiki page. + * @param string $contentBase64 The base64 encoded content of the wiki page. + * @param string|null $message Optional commit message summarizing the change. * * @return object|null * @since 3.2.0 @@ -67,9 +68,9 @@ class Wiki extends Api /** * Get a wiki page. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param string $pageName The name of the wiki page. + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. * * @return object|null * @since 3.2.0 @@ -95,10 +96,10 @@ class Wiki extends Api /** * Get all wiki pages. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param int $page Page number of results to return (1-based). - * @param int $limit Page size of results. + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param int $page Page number of results to return (1-based). + * @param int $limit Page size of results. * * @return array|null * @since 3.2.0 @@ -127,9 +128,9 @@ class Wiki extends Api /** * Delete a wiki page. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param string $pageName The name of the wiki page. + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. * * @return string * @since 3.2.0 @@ -155,12 +156,12 @@ class Wiki extends Api /** * Edit a wiki page. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param string $pageName The name of the wiki page. - * @param string $title The new title of the wiki page. - * @param string $content The new content of the wiki page. - * @param string $message The optional commit message summarizing the change. + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * @param string $title The new title of the wiki page. + * @param string $content The new content of the wiki page. + * @param string $message The optional commit message summarizing the change. * * @return object|null * @since 3.2.0 @@ -199,10 +200,10 @@ class Wiki extends Api /** * Get revisions of a wiki page. * - * @param string $owner The owner name. - * @param string $repo The repository name. - * @param string $pageName The name of the wiki page. - * @param int $page The page number of results to return (1-based). + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * @param int $page The page number of results to return (1-based). * * @return object|null * @since 3.2.0 @@ -226,7 +227,6 @@ class Wiki extends Api $this->uri->get($path) ) ); - } - + } } diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php index 9a5455deb..7598eb98b 100644 --- a/libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php @@ -19,7 +19,7 @@ use VDM\Joomla\Interfaces\Git\ApiInterface; /** - * The Gitea Api + * The Github Api * * @since 5.1.1 */ @@ -98,10 +98,11 @@ abstract class Api implements ApiInterface // for the rest of the container if ($backup) { - if ($url !== null) - { - $this->url = $this->uri->getUrl(); - } + // Github has only one URL + // if ($url !== null) + // { + // $this->url = $this->uri->getUrl(); + // } if ($token !== null) { @@ -109,10 +110,11 @@ abstract class Api implements ApiInterface } } - if ($url !== null) - { - $this->uri->setUrl($url); - } + // Github has only one URL + // if ($url !== null) + // { + // $this->uri->setUrl($url); + // } if ($token !== null) { @@ -128,11 +130,12 @@ abstract class Api implements ApiInterface **/ public function reset_(): void { - if ($this->url !== null) - { - $this->uri->setUrl($this->url); - $this->url = null; - } + // Github has only one URL + // if ($this->url !== null) + // { + // $this->uri->setUrl($this->url); + // $this->url = null; + // } if ($this->token !== null) { diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Factory.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Factory.php new file mode 100644 index 000000000..591819da6 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Factory.php @@ -0,0 +1,51 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Github; + + +use Joomla\DI\Container; +use VDM\Joomla\Github\Service\Utilities; +use VDM\Joomla\Componentbuilder\Power\Service\Github; +use VDM\Joomla\Interfaces\FactoryInterface; +use VDM\Joomla\Abstraction\Factory as ExtendingFactory; + + +/** + * Github Factory + * + * @since 5.1.1 + */ +abstract class Factory extends ExtendingFactory implements FactoryInterface +{ + /** + * Package Container + * + * @var Container|null + * @since 5.0.3 + **/ + protected static ?Container $container = null; + + /** + * Create a container object + * + * @return Container + * @since 3.2.0 + */ + protected static function createContainer(): Container + { + return (new Container()) + ->registerServiceProvider(new Utilities()) + ->registerServiceProvider(new Github()); + } + +} + diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Contents.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Contents.php index 9969c1327..ec86007a9 100644 --- a/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Contents.php +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Contents.php @@ -21,7 +21,7 @@ use VDM\Joomla\Github\Abstraction\Api; * * @since 5.1.1 */ -class Contents extends Api implements ContentsInterface +final class Contents extends Api implements ContentsInterface { /** * Get a file from a repository. diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Tags.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Tags.php new file mode 100644 index 000000000..e05d16349 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Tags.php @@ -0,0 +1,186 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Github\Repository; + + +use VDM\Joomla\Interfaces\Git\Repository\TagsInterface; +use VDM\Joomla\Github\Abstraction\Api; + + +/** + * The Github Repository Tags + * + * @since 5.1.1 + */ +final class Tags extends Api implements TagsInterface +{ + /** + * List a repository's tags + * + * @param string $owner The owner of the repo. + * @param string $repo The name of the repo. + * @param int|null $page The page number of results to return (1-based). + * @param int|null $limit The page size of results. GitHub default is 30, max 100. Here we fix it to 10. + * + * @return array|null + * @since 3.2.0 + */ + public function list( + string $owner, + string $repo, + ?int $page = 1, + ?int $limit = 10 + ): ?array { + $path = "/repos/{$owner}/{$repo}/tags"; + $uri = $this->uri->get($path); + + $uri->setVar('page', $page ?? 1); + $uri->setVar('per_page', $limit ?? 10); + + return $this->response->get( + $this->http->get($uri) + ); + } + + /** + * Get the tag object by tag name (loop until found or exhausted). + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $tag The tag name to find. + * + * @return object|null + * @since 3.2.0 + */ + public function get(string $owner, string $repo, string $tag): ?object + { + $page = 1; + $limit = 10; + + do { + $tags = $this->list($owner, $repo, $page, $limit); + + if (empty($tags)) + { + return null; + } + + foreach ($tags as $entry) + { + if (isset($entry->name) && $entry->name === $tag) + { + return $entry; + } + } + + $page++; + } while (count($tags) === $limit); + + return null; + } + + /** + * Get the annotated tag object by SHA. + * + * @param string $owner The owner of the repo. + * @param string $repo The repository name. + * @param string $sha The tag object SHA. + * + * @return object|null + * @since 3.2.0 + */ + public function sha(string $owner, string $repo, string $sha): ?object + { + $path = "/repos/{$owner}/{$repo}/git/tags/{$sha}"; + return $this->response->get( + $this->http->get($this->uri->get($path)) + ); + } + + /** + * Create a new annotated tag and attach it to the repository. + * + * GitHub requires two steps to create a tag: + * 1. Create an annotated tag object. + * 2. Create a reference to the tag under `refs/tags/*`. + * + * @param string $owner The owner of the repo. + * @param string $repo The repository name. + * @param string $tagName The name of the tag. + * @param string $target The SHA the tag points to (usually a commit SHA). + * @param string $message The tag message. + * + * @return object|null + * @since 3.2.0 + */ + public function create(string $owner, string $repo, string $tagName, string $target, string $message): ?object + { + // Step 1: Create the tag object + $tagObject = (object) [ + 'tag' => $tagName, + 'message' => $message, + 'object' => $target, + 'type' => 'commit' + ]; + + $tagResponse = $this->response->get( + $this->http->post( + $this->uri->get("/repos/{$owner}/{$repo}/git/tags"), + json_encode($tagObject) + ) + ); + + if (!isset($tagResponse->sha)) + { + return null; + } + + // Step 2: Create the ref pointing to the tag object + $refData = (object) [ + 'ref' => "refs/tags/{$tagName}", + 'sha' => $tagResponse->sha + ]; + + return $this->response->get( + $this->http->post( + $this->uri->get("/repos/{$owner}/{$repo}/git/refs"), + json_encode($refData) + ) + ); + } + + /** + * Delete a tag reference by tag name. + * + * GitHub deletes tags via refs. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $tag The tag name to delete. + * + * @return string Returns 'success' on successful deletion. + * @since 3.2.0 + */ + public function delete(string $owner, string $repo, string $tag): string + { + $path = "/repos/{$owner}/{$repo}/git/refs/tags/{$tag}"; + + return $this->response->get( + $this->http->delete( + $this->uri->get($path) + ), + 204, + 'success' + ); + } +} + diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Wiki.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Wiki.php new file mode 100644 index 000000000..ba6e9c345 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Repository/Wiki.php @@ -0,0 +1,166 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Github\Repository; + + +use VDM\Joomla\Interfaces\Git\Repository\WikiInterface; +use VDM\Joomla\Github\Abstraction\Api; +use Joomla\CMS\Uri\Uri; + + +/** + * The Github Repository Wiki + * + * @since 5.1.1 + */ +class Wiki extends Api implements WikiInterface +{ + /** + * Create a new wiki page or update it if it already exists. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param string $title Title of the wiki page. + * @param string $contentBase64 Base64-encoded Markdown content. + * @param string|null $message Optional commit message. + * + * @return object|null API response object or null on failure. + * @since 5.1.1 + */ + public function create( + string $owner, + string $repo, + string $title, + string $contentBase64, + ?string $message = null + ): ?object + { + return null; // github does not support wiki over API + } + + /** + * Retrieve the content of a specific wiki page. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param string $pageName Name of the page (excluding `.md`). + * + * @return object|null Page details including content and metadata, or null on failure. + * @since 5.1.1 + */ + public function get( + string $owner, + string $repo, + string $pageName + ): ?object + { + // Build the raw wiki URL + $url = "https://raw.githubusercontent.com/wiki/{$owner}/{$repo}/{$pageName}.md"; + + // Use a direct HTTP GET request (bypasses GitHub API) + $body = $this->response->get( + $this->http->get(new Uri($url), []) + ); + + return (object) [ + 'name' => "{$pageName}.md", + 'content' => base64_encode($body), + ]; + } + + /** + * List all wiki pages in the repository. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param int $page Pagination index (1-based). + * @param int $limit Number of results per page. + * + * @return array|null List of page metadata or null on failure. + * @since 5.1.1 + */ + public function pages( + string $owner, + string $repo, + int $page = 1, + int $limit = 10 + ): ?array + { + return null; // github does not support wiki over API + } + + /** + * Delete a wiki page from the repository. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param string $pageName Name of the page to delete (excluding `.md`). + * + * @return string 'success' on deletion, or error message if the page was not found. + * @since 5.1.1 + */ + public function delete( + string $owner, + string $repo, + string $pageName + ): string + { + return 'error'; // github does not support wiki over API + } + + /** + * Edit an existing wiki page. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param string $pageName Name of the page to edit (excluding `.md`). + * @param string $title New title of the page (used to rename if applicable). + * @param string $content Updated Markdown content. + * @param string|null $message Optional commit message. + * + * @return object|null API response object or null if the page doesn't exist. + * @since 5.1.1 + */ + public function edit( + string $owner, + string $repo, + string $pageName, + string $title, + string $content, + string $message = null + ): ?object + { + return null; // github does not support wiki over API + } + + /** + * Get the commit history (revisions) for a specific wiki page. + * + * @param string $owner Repository owner (user or organization). + * @param string $repo Repository name (without `.wiki`). + * @param string $pageName Name of the page to retrieve revisions for (excluding `.md`). + * @param int $page Pagination index (1-based). + * + * @return object|null API response object with commit history or null on failure. + * @since 5.1.1 + */ + public function revisions( + string $owner, + string $repo, + string $pageName, + int $page = 1 + ): ?object + { + return null; // github does not support wiki over API + } +} + diff --git a/libraries/vendor_jcb/VDM.Joomla.Github/src/Service/Utilities.php b/libraries/vendor_jcb/VDM.Joomla.Github/src/Service/Utilities.php index 2dabe2d5d..ed19f0fc2 100644 --- a/libraries/vendor_jcb/VDM.Joomla.Github/src/Service/Utilities.php +++ b/libraries/vendor_jcb/VDM.Joomla.Github/src/Service/Utilities.php @@ -14,6 +14,7 @@ namespace VDM\Joomla\Github\Service; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; +use VDM\Joomla\Utilities\Component\Helper; use VDM\Joomla\Github\Utilities\Http; use VDM\Joomla\Github\Utilities\Uri; use VDM\Joomla\Github\Utilities\Response; @@ -56,7 +57,9 @@ class Utilities implements ServiceProviderInterface */ public function getHttp(Container $container): Http { - return new Http(); + return new Http( + Helper::getParams('com_componentbuilder')->get('github_access_token') ?? null + ); } /** diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Compiler/Builder/PermissionDashboard.php b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Compiler/Builder/PermissionDashboard.php index ac3c8c43d..578a75d29 100644 --- a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Compiler/Builder/PermissionDashboard.php +++ b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Compiler/Builder/PermissionDashboard.php @@ -44,21 +44,25 @@ final class PermissionDashboard extends Registry implements Registryinterface use VarExport; /** - * Get the build permission dashboard code + * Get the build permission dashboard code. * - * @return string - * @since 3.2.0 + * @return string + * @since 3.2.0 + * @since 5.1.1 Changed to class property. */ public function build(): string { - if ($this->isActive()) - { - return PHP_EOL . Indent::_(2) . "//" . Line::_(__Line__, __Class__) - . " view access array" . PHP_EOL . Indent::_(2) - . "\$viewAccess = " . $this->varExport() . ';'; - } + $indent = Indent::_(1); + $docBlock = PHP_EOL . $indent . '/**' + . PHP_EOL . $indent . ' *' . Line::_(__LINE__, __CLASS__) . ' View access array.' + . PHP_EOL . $indent . ' *' + . PHP_EOL . $indent . ' * @var array' + . PHP_EOL . $indent . ' * @since 5.1.1' + . PHP_EOL . $indent . ' */'; - return ''; + $value = $this->isActive() ? $this->varExport(null, 1) : '[]'; + + return $docBlock . PHP_EOL . $indent . 'protected array $viewAccess = ' . $value . ';' . PHP_EOL; } } diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Power/Service/Github.php b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Power/Service/Github.php index 5034af963..5277309a3 100644 --- a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Power/Service/Github.php +++ b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Power/Service/Github.php @@ -15,6 +15,8 @@ namespace VDM\Joomla\Componentbuilder\Power\Service; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use VDM\Joomla\Github\Repository\Contents; +use VDM\Joomla\Github\Repository\Tags; +use VDM\Joomla\Github\Repository\Wiki; /** @@ -36,6 +38,12 @@ class Github implements ServiceProviderInterface { $container->alias(Contents::class, 'Github.Repository.Contents') ->share('Github.Repository.Contents', [$this, 'getContents'], true); + + $container->alias(Tags::class, 'Github.Repository.Tags') + ->share('Github.Repository.Tags', [$this, 'getTags'], true); + + $container->alias(Wiki::class, 'Github.Repository.Wiki') + ->share('Github.Repository.Wiki', [$this, 'getWiki'], true); } /** @@ -53,6 +61,40 @@ class Github implements ServiceProviderInterface $container->get('Github.Utilities.Uri'), $container->get('Github.Utilities.Response') ); + } + + /** + * Get the Tags class + * + * @param Container $container The DI container. + * + * @return Tags + * @since 5.1.1 + */ + public function getTags(Container $container): Tags + { + return new Tags( + $container->get('Github.Utilities.Http'), + $container->get('Github.Utilities.Uri'), + $container->get('Github.Utilities.Response') + ); + } + + /** + * Get the Wiki class + * + * @param Container $container The DI container. + * + * @return Wiki + * @since 5.1.1 + */ + public function getWiki(Container $container): Wiki + { + return new Wiki( + $container->get('Github.Utilities.Http'), + $container->get('Github.Utilities.Uri'), + $container->get('Github.Utilities.Response') + ); } } diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/Version.php b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/Version.php new file mode 100644 index 000000000..71fe04cf2 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/Version.php @@ -0,0 +1,386 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Componentbuilder\Remote; + + +use Joomla\CMS\Language\Text; +use VDM\Joomla\Github\Factory as Github; +use VDM\Joomla\Gitea\Factory as Gitea; +use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper; + + +/** + * Get Remote Version + * + * @since 5.1.1 + */ +final class Version +{ + /** + * GitHub organization name. + * + * @var string + * @since 5.1.1 + */ + protected string $githubOrg; + + /** + * GitHub repository name. + * + * @var string + * @since 5.1.1 + */ + protected string $githubRepo; + + /** + * Gitea organization name. + * + * @var string + * @since 5.1.1 + */ + protected string $giteaOrg; + + /** + * Gitea repository name. + * + * @var string + * @since 5.1.1 + */ + protected string $giteaRepo; + + /** + * Constructor to set repository organization and name for both GitHub and Gitea. + * + * @param string $githubOrg GitHub organization name. + * @param string $githubRepo GitHub repository name. + * @param string $giteaOrg Gitea organization name. + * @param string $giteaRepo Gitea repository name. + * + * @since 5.1.1 + */ + public function __construct(string $githubOrg, string $githubRepo, string $giteaOrg, string $giteaRepo) + { + $this->githubOrg = $githubOrg; + $this->githubRepo = $githubRepo; + $this->giteaOrg = $giteaOrg; + $this->giteaRepo = $giteaRepo; + } + + /** + * Get the current version notice. + * + * Compares the installed version of the component with the latest available + * version from the repository tags and returns an appropriate message. + * + * @param string|null $version Optional version to compare if manifest version not found. + * + * @return array The array with 'notice' or 'error' and optional 'github-error' / 'gitea-error'. + * @since 5.1.1 + */ + public function get(?string $version = null): array + { + $defaultDownloadLink = 'https://git.vdm.dev/joomla/pkg-component-builder/releases'; + + $manifest = ComponentbuilderHelper::manifest(); + $localVersion = (string) ($manifest->version ?? $version ?? '1.0.0'); + $major = explode('.', $localVersion)[0] ?? '1'; + + $errors = [ + 'error' => Text::sprintf( + 'There was an error getting the %sVersion details.', + '' + ) + ]; + + $tags = $this->getRepositoryTags($errors); + + if (empty($tags) || !isset($tags[0]->name)) + { + return $this->mergeErrors($errors); + } + + $grouped = $this->groupTagsByType($tags, $major); + + $latestStableTag = $grouped['stable'][0] ?? null; + $latestStableVer = $latestStableTag ? ltrim($latestStableTag->name, 'vV') : '1.0.0'; + $latestStableLink = $latestStableTag->zipball_url ?? $defaultDownloadLink; + + $versionType = $this->getVersionType($localVersion); + $versionCompare = version_compare($localVersion, $latestStableVer); + + // Handle pre-release versions + if ($versionType !== 'stable') + { + $isLatestPre = $this->isLatestPreRelease($localVersion, $grouped['pre']); + + $state = $isLatestPre ? Text::_('COM_COMPONENTBUILDER_PRE_RELEASE') : Text::_('COM_COMPONENTBUILDER_OUT_OF_DATE'); + $statement = sprintf( + ' %s', + $state + ); + + $color = $isLatestPre ? '#F7B033' : 'red'; + $state = $isLatestPre + ? Text::sprintf("COM_COMPONENTBUILDER_THANK_YOU_FOR_TESTING_THE_S_RELEASE_YOURE_A_JCB_HERO", strtoupper($versionType)) + : Text::sprintf("COM_COMPONENTBUILDER_GRAB_THE_LATEST_S_TESTING_RELEASE", strtoupper($versionType)); + + $notice = sprintf( + ' %s', + $color, $grouped['pre'][0]->zipball_url ?? $defaultDownloadLink, $state, $statement + ); + + return ['notice' => $notice]; + } + + // Stable and up-to-date + if ($versionCompare === 0) + { + $notice = sprintf( + ' %s', + Text::_('COM_COMPONENTBUILDER_UP_TO_DATE') + ); + + if (!empty($grouped['pre'])) + { + $notice = sprintf( + ' %s', + $grouped['pre'][0]->zipball_url ?? $defaultDownloadLink, + Text::_('COM_COMPONENTBUILDER_HELP_US_TEST_THE_UPCOMING_RELEASE'), + $notice + ); + } + + return ['notice' => $notice]; + } + + // Stable but outdated + return ['notice' => sprintf( + ' %s ' . + '%s', + Text::_('COM_COMPONENTBUILDER_OUT_OF_DATE') . '!', + $latestStableLink, + Text::_('COM_COMPONENTBUILDER_YOU_CAN_DIRECTLY_DOWNLOAD_THE_LATEST_UPDATE_OR_USE_THE_JOOMLA_UPDATE_AREA'), + Text::_('COM_COMPONENTBUILDER_DOWNLOAD_UPDATE') . '!' + )]; + } + + /** + * Check if the local pre-release version is the latest. + * + * @param string $localVersion The current local version. + * @param array $preTags All matching pre-release tags. + * + * @return bool + * @since 5.1.1 + */ + protected function isLatestPreRelease(string $localVersion, array $preTags): bool + { + if (empty($preTags)) + { + return false; + } + + usort($preTags, static fn($a, $b) => version_compare($b->name, $a->name)); + + $latestPre = ltrim($preTags[0]->name, 'vV'); + + return version_compare($localVersion, $latestPre) === 0; + } + + /** + * Fetch tags from GitHub or fallback to various Gitea instances. + * + * Appends source keys to the return array on failure. + * + * @param array &$errors The response array to populate error messages into. + * + * @return array List of tags or an empty array. + * @since 5.1.1 + */ + protected function getRepositoryTags(array &$errors): array + { + // Attempt GitHub fetch + if ($tags = $this->tryFetchTags('github', $errors)) + { + return $tags; + } + + // Try default VDM Gitea instance + if ($tags = $this->tryFetchTags('gitea', $errors)) + { + return $tags; + } + + // Try alternative Gitea hosts + $alternatives = [ + 'codeberg' => 'https://codeberg.org', + 'tildegit' => 'https://tildegit.org', + 'disroot' => 'https://git.disroot.org', + ]; + + foreach ($alternatives as $key => $url) + { + Gitea::_('Gitea.Repository.Tags')->load_($url, ''); + if ($tags = $this->tryFetchTags($key, $errors)) + { + return $tags; + } + } + + // Final reset to default host + return []; + } + + /** + * Attempt to fetch tags from a given source and record any error. + * + * @param string $source One of: 'github', 'gitea', 'codeberg', 'tildegit', 'disroot'. + * @param array &$errors Reference to return array for error recording. + * + * @return array|null List of tags or null on failure. + * @since 5.1.1 + */ + protected function tryFetchTags(string $source, array &$errors): ?array + { + try { + return match ($source) { + 'github' => Github::_('Github.Repository.Tags')->list($this->githubOrg, $this->githubRepo), + default => Gitea::_('Gitea.Repository.Tags')->list($this->giteaOrg, $this->giteaRepo), + }; + } catch (\Throwable $e) { + $errors["{$source}-error"] = $e->getMessage(); + } finally { + if ($source !== 'github' && $source !== 'gitea') { + Gitea::_('Gitea.Repository.Tags')->reset_(); + } + } + + return null; + } + + /** + * Groups and sorts tags into stable and pre-release arrays. + * + * @param array $tags List of repository tags. + * @param string $major Major version prefix to match. + * + * @return array{stable: array, pre: array} + * @since 5.1.1 + */ + protected function groupTagsByType(array $tags, string $major): array + { + $stable = []; + $pre = []; + + foreach ($tags as $tag) + { + if (!isset($tag->name) || strpos($tag->name, 'v' . $major) !== 0) + { + continue; + } + + $version = strtolower($tag->name); + + if (preg_match('/-(alpha|beta|rc)\d*/', $version)) { + $pre[] = $tag; + } else { + $stable[] = $tag; + } + } + + usort($stable, static fn($a, $b) => version_compare($b->name, $a->name)); + usort($pre, static fn($a, $b) => version_compare($b->name, $a->name)); + + return ['stable' => $stable, 'pre' => $pre]; + } + + /** + * Determine the version type from the string. + * + * @param string $version The version string to analyze. + * + * @return string 'stable', 'alpha', 'beta' or 'rc'. + * @since 5.1.1 + */ + protected function getVersionType(string $version): string + { + $version = strtolower($version); + + if (str_contains($version, '-alpha')) + { + return 'alpha'; + } + + if (str_contains($version, '-beta')) + { + return 'beta'; + } + + if (str_contains($version, '-rc')) + { + return 'rc'; + } + + return 'stable'; + } + + /** + * Merge repository fetch errors into the error message as a toggleable Bootstrap block. + * + * This enhances the 'error' message by appending a red icon and a collapsible + * section with the actual GitHub/Gitea error messages. + * + * @param array $errors The array containing at least 'error' and optionally error details. + * + * @return array The modified array with a richer 'error' message. + * @since 5.1.1 + */ + protected function mergeErrors(array $errors): array + { + $bucket = []; + + foreach ($errors as $key => $value) + { + if ($key !== 'error') + { + $source = ucfirst(explode('-', $key)[0]); + $bucket[] = '

  • ' . $source . ': ' . htmlspecialchars($value) . '
  • '; + } + } + + if (empty($bucket)) + { + return $errors; + } + + $uid = uniqid('version-error-'); + + $toggle = sprintf( + ' ', + $uid, + $uid, + Text::_('COM_COMPONENTBUILDER_DETAILS') + ); + + $details = sprintf( + '
      %s
    ', + $uid, + implode('', $bucket) + ); + + $errors['error'] .= $toggle . $details; + + return $errors; + } +} + diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/index.html b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla/src/Componentbuilder/Remote/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/TagsInterface.php b/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/TagsInterface.php new file mode 100644 index 000000000..edd8eb983 --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/TagsInterface.php @@ -0,0 +1,107 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Interfaces\Git\Repository; + + +use VDM\Joomla\Interfaces\Git\ApiInterface; + + +/** + * The Git Repository Tags Interface + * + * @since 5.1.1 + */ +interface TagsInterface extends ApiInterface +{ + /** + * List a repository's tags + * + * @param string $owner The owner of the repo. + * @param string $repo The name of the repo. + * @param int|null $page The page number of results to return (1-based). + * @param int|null $limit The page size of results, default maximum page size is 10. + * + * @return array|null + * @since 3.2.0 + **/ + public function list( + string $owner, + string $repo, + ?int $page = 1, + ?int $limit = 10 + ): ?array; + + /** + * Get the tag of a repository by tag name. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $tag The tag name. + * + * @return object|null + * @since 3.2.0 + **/ + public function get(string $owner, string $repo, string $tag): ?object; + + /** + * Get the tag object of an annotated tag (not lightweight tags). + * + * @param string $owner The owner of the repo. + * @param string $repo The name of the repo. + * @param string $sha The sha of the tag. The Git tags API only supports annotated tag objects, not lightweight tags. + * + * @return object|null + * @since 3.2.0 + **/ + public function sha( + string $owner, + string $repo, + string $sha + ): ?object; + + /** + * Create a new git tag in a repository. + * + * @param string $owner The owner of the repo. + * @param string $repo The name of the repo. + * @param string $tagName The name of the tag. + * @param string $target The SHA of the git object this is tagging. + * @param string $message The tag message. + * + * @return object|null + * @since 3.2.0 + **/ + public function create( + string $owner, + string $repo, + string $tagName, + string $target, + string $message + ): ?object; + + /** + * Delete a repository's tag by name. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $tag The tag name. + * + * @return string + * @since 3.2.0 + **/ + public function delete( + string $owner, + string $repo, + string $tag + ): string; +} + diff --git a/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/WikiInterface.php b/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/WikiInterface.php new file mode 100644 index 000000000..bf169569f --- /dev/null +++ b/libraries/vendor_jcb/VDM.Joomla/src/Interfaces/Git/Repository/WikiInterface.php @@ -0,0 +1,135 @@ + + * @git Joomla Component Builder + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\Interfaces\Git\Repository; + + +use VDM\Joomla\Interfaces\Git\ApiInterface; + + +/** + * The Git Repository Wiki Interface + * + * @since 5.1.1 + */ +interface WikiInterface extends ApiInterface +{ + /** + * Create a wiki page. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $title The title of the wiki page. + * @param string $contentBase64 The base64 encoded content of the wiki page. + * @param string|null $message Optional commit message summarizing the change. + * + * @return object|null + * @since 3.2.0 + **/ + public function create( + string $owner, + string $repo, + string $title, + string $contentBase64, + ?string $message = null + ): ?object; + + /** + * Get a wiki page. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * + * @return object|null + * @since 3.2.0 + **/ + public function get( + string $owner, + string $repo, + string $pageName + ): ?object; + + /** + * Get all wiki pages. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param int $page Page number of results to return (1-based). + * @param int $limit Page size of results. + * + * @return array|null + * @since 3.2.0 + **/ + public function pages( + string $owner, + string $repo, + int $page = 1, + int $limit = 10 + ): ?array; + + /** + * Delete a wiki page. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * + * @return string + * @since 3.2.0 + **/ + public function delete( + string $owner, + string $repo, + string $pageName + ): string; + + /** + * Edit a wiki page. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * @param string $title The new title of the wiki page. + * @param string $content The new content of the wiki page. + * @param string $message The optional commit message summarizing the change. + * + * @return object|null + * @since 3.2.0 + **/ + public function edit( + string $owner, + string $repo, + string $pageName, + string $title, + string $content, + string $message = null + ): ?object; + + /** + * Get revisions of a wiki page. + * + * @param string $owner The owner name. + * @param string $repo The repository name. + * @param string $pageName The name of the wiki page. + * @param int $page The page number of results to return (1-based). + * + * @return object|null + * @since 3.2.0 + **/ + public function revisions( + string $owner, + string $repo, + string $pageName, + int $page = 1 + ): ?object; +} +