diff --git a/administrator/components/com_guidedtours/src/Controller/AjaxController.php b/administrator/components/com_guidedtours/src/Controller/AjaxController.php index 0dbf1929e04cb..2e6b4416f6318 100644 --- a/administrator/components/com_guidedtours/src/Controller/AjaxController.php +++ b/administrator/components/com_guidedtours/src/Controller/AjaxController.php @@ -38,87 +38,90 @@ public function fetchUserState() $user = $this->app->getIdentity(); $tourId = $this->app->input->getInt('tid', 0); - $stepNumber = $this->app->input->getString('sid', ''); + $stepNumber = $this->app->input->getInt('sid', 0); $context = $this->app->input->getString('context', ''); - if ($user != null && $user->id > 0) { - $actionState = ''; - - switch ($context) { - case 'tour.complete': - $actionState = 'completed'; - break; - case 'tour.cancel': - $actionState = 'delayed'; - break; - case 'tour.skip': - $actionState = 'skipped'; - break; - } + if ($user == null || $user->id <= 0) { + echo new JsonResponse(['success' => false, 'tourId' => $tourId], Text::_('COM_GUIDEDTOURS_USERSTATE_CONNECTEDONLY'), true); + $this->app->close(); + } + + if (!\in_array($context, ['tour.complete', 'tour.cancel', 'tour.skip'])) { + echo new JsonResponse(['success' => false, 'tourId' => $tourId], Text::_('COM_GUIDEDTOURS_USERSTATE_WRONGCONTEXT'), true); + $this->app->close(); + } - PluginHelper::importPlugin('guidedtours'); - - // event onBeforeTourSaveUserState before save user tour state - $beforeEvent = AbstractEvent::create( - 'onBeforeTourSaveUserState', - [ - 'subject' => new \stdClass(), - 'tourId' => $tourId, - 'actionState' => $actionState, - 'stepNumber' => $stepNumber, - ] - ); - - $this->app->getDispatcher()->dispatch('onBeforeTourSaveUserState', $beforeEvent); - - // Save the tour state only when the tour auto-starts. - $tourModel = $this->getModel('Tour', 'Administrator'); - if ($tourModel->isAutostart($tourId)) { - $result = $tourModel->saveTourUserState($tourId, $actionState); - if ($result) { - $message = Text::sprintf('COM_GUIDEDTOURS_USERSTATE_STATESAVED', $user->id, $tourId); - } else { - $message = Text::sprintf('COM_GUIDEDTOURS_USERSTATE_STATENOTSAVED', $user->id, $tourId); - } + if ($tourId <= 0) { + echo new JsonResponse(['success' => false, 'tourId' => $tourId], Text::_('COM_GUIDEDTOURS_USERSTATE_BADTOURID'), true); + $this->app->close(); + } + + $actionState = ''; + + switch ($context) { + case 'tour.complete': + $actionState = 'completed'; + break; + case 'tour.cancel': + $actionState = 'delayed'; + break; + case 'tour.skip': + $actionState = 'skipped'; + break; + } + + PluginHelper::importPlugin('guidedtours'); + + // event onBeforeTourSaveUserState before save user tour state + $beforeEvent = AbstractEvent::create( + 'onBeforeTourSaveUserState', + [ + 'subject' => new \stdClass(), + 'tourId' => $tourId, + 'actionState' => $actionState, + 'stepNumber' => $stepNumber, + ] + ); + + $this->app->getDispatcher()->dispatch('onBeforeTourSaveUserState', $beforeEvent); + + // Save the tour state only when the tour auto-starts. + $tourModel = $this->getModel('Tour', 'Administrator'); + if ($tourModel->isAutostart($tourId)) { + $result = $tourModel->saveTourUserState($tourId, $actionState); + if ($result) { + $message = Text::sprintf('COM_GUIDEDTOURS_USERSTATE_STATESAVED', $user->id, $tourId); } else { - $result = false; $message = Text::sprintf('COM_GUIDEDTOURS_USERSTATE_STATENOTSAVED', $user->id, $tourId); } - - // event onAfterTourSaveUserState after save user tour state (may override message) - $afterEvent = AbstractEvent::create( - 'onAfterTourSaveUserState', - [ - 'subject' => new \stdClass(), - 'tourId' => $tourId, - 'actionState' => $actionState, - 'stepNumber' => $stepNumber, - 'result' => $result, - 'message' => &$message, - ] - ); - - $this->app->getDispatcher()->dispatch('onAfterTourSaveUserState', $afterEvent); - - // Construct the response data - $data = [ - 'tourId' => $tourId, - 'stepId' => $stepNumber, - 'context' => $context, - 'state' => $actionState, - ]; - echo new JsonResponse($data, $message); - $this->app->close(); } else { - // Construct the response data - $data = [ - 'success' => false, - 'tourId' => $tourId, - ]; - - $message = Text::_('COM_GUIDEDTOURS_USERSTATE_CONNECTEDONLY'); - echo new JsonResponse($data, $message, true); - $this->app->close(); + $result = false; + $message = Text::sprintf('COM_GUIDEDTOURS_USERSTATE_STATENOTSAVED', $user->id, $tourId); } + + // event onAfterTourSaveUserState after save user tour state (may override message) + $afterEvent = AbstractEvent::create( + 'onAfterTourSaveUserState', + [ + 'subject' => new \stdClass(), + 'tourId' => $tourId, + 'actionState' => $actionState, + 'stepNumber' => $stepNumber, + 'result' => $result, + 'message' => &$message, + ] + ); + + $this->app->getDispatcher()->dispatch('onAfterTourSaveUserState', $afterEvent); + + // Construct the response data + $data = [ + 'tourId' => $tourId, + 'stepId' => $stepNumber, + 'context' => $context, + 'state' => $actionState, + ]; + echo new JsonResponse($data, $message); + $this->app->close(); } } diff --git a/administrator/components/com_guidedtours/src/Dispatcher/Dispatcher.php b/administrator/components/com_guidedtours/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..31a2470d6aa5f --- /dev/null +++ b/administrator/components/com_guidedtours/src/Dispatcher/Dispatcher.php @@ -0,0 +1,43 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Component\Guidedtours\Administrator\Dispatcher; + +use Joomla\CMS\Access\Exception\NotAllowed; +use Joomla\CMS\Dispatcher\ComponentDispatcher; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * ComponentDispatcher class for com_guidedtours + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends ComponentDispatcher +{ + /** + * Method to check component access permission + * + * @return void + * + * @throws \Exception|NotAllowed + */ + protected function checkAccess() + { + $command = $this->input->getCmd('task', 'display'); + if ($this->app->isClient('administrator') && $command == 'ajax.fetchUserState') { + return; + } + + parent::checkAccess(); + } +} diff --git a/administrator/language/en-GB/com_guidedtours.ini b/administrator/language/en-GB/com_guidedtours.ini index 465e8c30a082e..9e8a9aef29e78 100644 --- a/administrator/language/en-GB/com_guidedtours.ini +++ b/administrator/language/en-GB/com_guidedtours.ini @@ -94,8 +94,10 @@ COM_GUIDEDTOURS_TYPE_REDIRECT_URL_DESC="Enter the relative URL of the page you w COM_GUIDEDTOURS_TYPE_REDIRECT_URL_LABEL="Relative URL" COM_GUIDEDTOURS_URL_LABEL="Relative URL" COM_GUIDEDTOURS_URL_DESC="Enter the relative URL of the page from where you want to Start the tour, e.g administrator/index.php?option=com_guidedtours&view=tours for the tours' list page." +COM_GUIDEDTOURS_USERSTATE_BADTOURID="The Tour needs to have a positive id." ; 'Tour User states' are conditions in which a guided tour user leaves a tour, either by cancelling, completing or skipping a tour. COM_GUIDEDTOURS_USERSTATE_CONNECTEDONLY="The recording of User states for a tour is only available to logged-in users." COM_GUIDEDTOURS_USERSTATE_STATENOTSAVED="The User state was not saved for user %1$s tour %2$s." COM_GUIDEDTOURS_USERSTATE_STATESAVED="The User state was saved for user %1$s tour %2$s." +COM_GUIDEDTOURS_USERSTATE_WRONGCONTEXT="The Tour User state context is incorrect." COM_GUIDEDTOURS_XML_DESCRIPTION="Component for managing Guided Tours functionality."