diff --git a/ajax/dropdownZone.php b/ajax/dropdownZone.php deleted file mode 100644 index 1ed765d2..00000000 --- a/ajax/dropdownZone.php +++ /dev/null @@ -1,56 +0,0 @@ -. - * - * ------------------------------------------------------------------------- - */ - -use GlpiPlugin\Carbon\Source_Zone; -use GlpiPlugin\Carbon\Zone; - -include(__DIR__ . '/../../../inc/includes.php'); - -// Check if plugin is activated... -if (!Plugin::isPluginActive('carbon')) { - http_response_code(404); - die(); -} - -if (!Zone::canView()) { - http_response_code(403); - die(); -} - -$source_zone_table = Source_Zone::getTable(); -$zone_table = Zone::getTable(); -$source_id = (int) $_POST['plugin_carbon_sources_id']; -Zone::dropdown([ - 'rand' => (int) $_POST['dom_id'], - 'condition' => Zone::getRestrictBySourceCondition($source_id), - 'specific_tags' => ($source_id === 0 ? ['disabled' => 'disabled'] : []), -]); diff --git a/ajax/toggleZoneDownload.php b/ajax/toggleZoneDownload.php deleted file mode 100644 index a3f8fe0a..00000000 --- a/ajax/toggleZoneDownload.php +++ /dev/null @@ -1,69 +0,0 @@ -. - * - * ------------------------------------------------------------------------- - */ - -use Config as GlpiConfig; -use GlpiPlugin\Carbon\Source; -use GlpiPlugin\Carbon\Source_Zone; - -include(__DIR__ . '/../../../inc/includes.php'); - -// Check if plugin is activated... -if (!Plugin::isPluginActive('carbon')) { - echo __('Not found.', 'carbon'); - http_response_code(404); - die(); -} - -if (!Source::canView() || ! GlpiConfig::canUpdate()) { - // Will die - echo __('Access denied.', 'carbon'); - http_response_code(403); - die(); -} - -if (!isset($_GET['id'])) { - echo __('Bad request.', 'carbon'); - http_response_code(400); - die(); -} - -$source_zone = new Source_Zone(); -if (!$source_zone->getFromDB($_GET['id'])) { - echo __('Item not found.', 'carbon'); - http_response_code(403); - die(); -} -if (!$source_zone->toggleZone()) { - echo __('Update failed.', 'carbon'); - http_response_code(500); - die(); -} diff --git a/composer.json b/composer.json index e9a9a0b1..f1537348 100644 --- a/composer.json +++ b/composer.json @@ -8,8 +8,7 @@ "php-http/message-factory": "^1.1" }, "require-dev": { - "glpi-project/tools": "^0.8.1", - "marcocesarato/php-conventional-changelog": "^1.17" + "glpi-project/tools": "^0.8.1" }, "config": { "optimize-autoloader": true, diff --git a/composer.lock b/composer.lock index 3a534dbe..a39801f4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a821ef4c2ae32d2c6dce28a1a3b4ceb9", + "content-hash": "e9d627568b1c399e0361e80bb7cdef54", "packages": [ { "name": "clue/stream-filter", @@ -693,84 +693,6 @@ }, "time": "2025-10-14T10:26:06+00:00" }, - { - "name": "marcocesarato/php-conventional-changelog", - "version": "1.17.3", - "source": { - "type": "git", - "url": "https://github.com/marcocesarato/php-conventional-changelog.git", - "reference": "c49b4a69ddf9ecbf055e8029c65e54a956d7ffa2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/marcocesarato/php-conventional-changelog/zipball/c49b4a69ddf9ecbf055e8029c65e54a956d7ffa2", - "reference": "c49b4a69ddf9ecbf055e8029c65e54a956d7ffa2", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": ">=7.1.3", - "symfony/console": "^4 || ^5 || ^6 || ^7 || ^8" - }, - "require-dev": { - "brainmaestro/composer-git-hooks": "^2.8", - "friendsofphp/php-cs-fixer": "^3.8", - "php-mock/php-mock": "^2.3", - "php-mock/php-mock-phpunit": "^2.6", - "phpunit/phpunit": "^9.6" - }, - "bin": [ - "conventional-changelog" - ], - "type": "library", - "extra": { - "hooks": { - "pre-push": "composer check-cs", - "post-merge": "composer install", - "pre-commit": "composer fix-cs" - } - }, - "autoload": { - "psr-4": { - "ConventionalChangelog\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "Marco Cesarato", - "email": "cesarato.developer@gmail.com" - } - ], - "description": "Generate changelogs and release notes from a project's commit messages and metadata and automate versioning with semver.org and conventionalcommits.org", - "keywords": [ - "changelog", - "commit", - "commits", - "convention", - "conventional", - "conventional-changelog", - "conventional-changelog-preset", - "conventional-commit", - "conventional-commits", - "conventionalcommits", - "generation", - "git", - "history", - "php", - "readme", - "tag" - ], - "support": { - "issues": "https://github.com/marcocesarato/php-conventional-changelog/issues", - "source": "https://github.com/marcocesarato/php-conventional-changelog/tree/v1.17.3" - }, - "time": "2026-01-21T11:40:14+00:00" - }, { "name": "psr/container", "version": "2.0.2", diff --git a/phpstan.neon b/phpstan.neon index c02769b3..55b0307c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,7 +8,6 @@ parameters: paths: - src - front - - ajax - install - hook.php - setup.php diff --git a/rector.php b/rector.php index 69b3bb42..8ca924aa 100644 --- a/rector.php +++ b/rector.php @@ -40,7 +40,6 @@ return RectorConfig::configure() ->withPaths([ - __DIR__ . '/ajax', __DIR__ . '/front', __DIR__ . '/install', __DIR__ . '/public', diff --git a/src/Controller/AjaxController.php b/src/Controller/AjaxController.php new file mode 100644 index 00000000..c8f9faa2 --- /dev/null +++ b/src/Controller/AjaxController.php @@ -0,0 +1,106 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Controller; + +use Config as GlpiConfig; +use Glpi\Controller\AbstractController; +use Glpi\Http\Firewall; +use Glpi\Security\Attribute\SecurityStrategy; +use GlpiPlugin\Carbon\Source; +use GlpiPlugin\Carbon\Source_Zone; +use GlpiPlugin\Carbon\Zone; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Attribute\Route; + +class AjaxController extends AbstractController +{ + #[SecurityStrategy(Firewall::STRATEGY_AUTHENTICATED)] + #[Route( + path: 'ajax/dropdownZone.php', + name: 'ajax dropdownZone', + methods: ['GET', 'POST'] + )] + public function showDropdownBySourceCondition(Request $request): Response + { + // if method is GET, then throw an exception, workaround bug in GLPI up to 11.0.7 + if ($request->isMethod('GET')) { + return new Response('', 403); + } + + if (!Zone::canView()) { + return new Response('', 403); + } + + $source_id = (int) $_POST['plugin_carbon_sources_id']; + $html = Zone::dropdown([ + 'display' => false, + 'rand' => (int) $request->request->get('dom_id'), + 'condition' => Zone::getRestrictBySourceCondition($source_id), + 'specific_tags' => ($source_id === 0 ? ['disabled' => 'disabled'] : []), + ]); + return new Response($html); + } + + #[SecurityStrategy(Firewall::STRATEGY_AUTHENTICATED)] + #[Route( + path: 'ajax/toggleZoneDownload.php', + name: 'ajax toggle zone download flag', + methods: ['GET', 'POST'] + )] + public function toggleZoneDownload(Request $request): Response + { + // if method is GET, then throw an exception, workaround bug in GLPI up to 11.0.7 + if ($request->isMethod('GET')) { + return new Response('', 403); + } + + if (!Source::canView() || ! GlpiConfig::canUpdate()) { + return new Response(__('Access denied.', 'carbon'), 403); + } + + if (!isset($_POST['id'])) { + return new Response(__('Bad request.', 'carbon'), 400); + } + + $source_zone = new Source_Zone(); + if (!$source_zone->getFromDB($request->request->get('id'))) { + return new Response(__('Item not found.', 'carbon'), 403); + } + if (!$source_zone->toggleZone()) { + return new Response(__('Update failed.', 'carbon'), 500); + } + + return new Response(); + } +} diff --git a/src/Location.php b/src/Location.php index 8d3af569..735311c5 100644 --- a/src/Location.php +++ b/src/Location.php @@ -124,7 +124,7 @@ public function prepareInputForUpdate($input) } } - if (($input['plugin_carbon_sources_id'] ?? 0) == 0) { + if (isset($input['plugin_carbon_sources_id']) && $input['plugin_carbon_sources_id'] == 0) { $input['plugin_carbon_sources_zones_id'] = 0; } diff --git a/src/Source_Zone.php b/src/Source_Zone.php index c485486f..a3d7fd07 100644 --- a/src/Source_Zone.php +++ b/src/Source_Zone.php @@ -43,6 +43,7 @@ use InvalidArgumentException; use Location as GlpiLocation; use Override; +use Session; class Source_Zone extends CommonDBRelation { @@ -196,14 +197,18 @@ public static function showForSource(CommonDBTM $item) // At least 1 entry then add JS to toggle the state of zones echo Html::scriptBlock(' var plugin_carbon_toggleZone = function (id) { - fetch(CFG_GLPI["root_doc"] + "/plugins/carbon/ajax/toggleZoneDownload.php?id=" + id).then(response => { - if (response.status === 200) { - reloadTab(); - } else { - response.text().then(function (text) { - glpi_toast_error(text) - }); - } + var csrfToken = "' . Session::getNewCSRFToken() . '"; + var formData = new FormData(); + formData.append("_glpi_csrf_token", csrfToken); + formData.append("id", id); + fetch(CFG_GLPI["root_doc"] + "/plugins/carbon/ajax/toggleZoneDownload.php", { + method: "POST", + headers: { + "X-Glpi-Csrf-Token": csrfToken + }, + body: formData, + }).then(response => { + reloadTab(); }); }; '); @@ -295,14 +300,18 @@ public static function showForZone(CommonDBTM $item) // At least 1 entry then add JS to toggle the state of zones echo Html::scriptBlock(' var plugin_carbon_toggleZone = function (id) { - fetch(CFG_GLPI["root_doc"] + "/plugins/carbon/ajax/toggleZoneDownload.php?id=" + id).then(response => { - if (response.status === 200) { - reloadTab(); - } else { - response.text().then(function (text) { - glpi_toast_error(text) - }); - } + var csrfToken = "' . Session::getNewCSRFToken() . '"; + var formData = new FormData(); + formData.append("_glpi_csrf_token", csrfToken); + formData.append("id", id); + fetch(CFG_GLPI["root_doc"] + "/plugins/carbon/ajax/toggleZoneDownload.php", { + method: "POST", + headers: { + "X-Glpi-Csrf-Token": csrfToken + }, + body: formData, + }).then(response => { + reloadTab(); }); }; ');