From 43e2e62be4dce5218c47eb5f8218c53c8ab43c14 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Fri, 9 Feb 2024 11:47:42 +0800 Subject: [PATCH] MDL-80871 tool_usertours: Allow tours to ignore completion The use-case here is for tours which must be shown on every page load. The tour still needs to be ended for the current page, but should be shown again on the next time the page is loaded. --- .../tool/usertours/classes/external/tour.php | 1 + admin/tool/usertours/classes/helper.php | 2 +- .../classes/local/forms/edittour.php | 12 ++++++ admin/tool/usertours/classes/manager.php | 1 + admin/tool/usertours/classes/tour.php | 37 ++++++++++++++++++ .../tool/usertours/lang/en/tool_usertours.php | 3 ++ .../behat/tour_prevents_completion.feature | 29 ++++++++++++++ admin/tool/usertours/tests/tour_test.php | 38 ++++++++++++++++--- 8 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 admin/tool/usertours/tests/behat/tour_prevents_completion.feature diff --git a/admin/tool/usertours/classes/external/tour.php b/admin/tool/usertours/classes/external/tour.php index 0430b1febe4..9ecad8e43ac 100644 --- a/admin/tool/usertours/classes/external/tour.php +++ b/admin/tool/usertours/classes/external/tour.php @@ -189,6 +189,7 @@ class tour extends external_api { self::validate_context($context); $tour = tourinstance::instance($params['tourid']); + $tour->mark_user_completed(); \tool_usertours\event\tour_ended::create([ diff --git a/admin/tool/usertours/classes/helper.php b/admin/tool/usertours/classes/helper.php index f782127cc89..8327dbd0ed4 100644 --- a/admin/tool/usertours/classes/helper.php +++ b/admin/tool/usertours/classes/helper.php @@ -21,9 +21,9 @@ use core\output\inplace_editable; /** * Tour helper. * - * @package tool_usertours * @copyright 2016 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package tool_usertours */ class helper { /** diff --git a/admin/tool/usertours/classes/local/forms/edittour.php b/admin/tool/usertours/classes/local/forms/edittour.php index 165de32bc55..cf6f50402cd 100644 --- a/admin/tool/usertours/classes/local/forms/edittour.php +++ b/admin/tool/usertours/classes/local/forms/edittour.php @@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); require_once($CFG->libdir . '/formslib.php'); use tool_usertours\helper; +use tool_usertours\tour; /** * Form for editing tours. @@ -88,6 +89,17 @@ class edittour extends \moodleform { $mform->addElement('checkbox', 'displaystepnumbers', get_string('displaystepnumbers', 'tool_usertours')); $mform->addHelpButton('displaystepnumbers', 'displaystepnumbers', 'tool_usertours'); + $mform->addElement( + 'select', + 'showtourwhen', + get_string('showtourwhen', 'tool_usertours'), + [ + tour::SHOW_TOUR_UNTIL_COMPLETE => get_string('showtouruntilcomplete', 'tool_usertours'), + tour::SHOW_TOUR_ON_EACH_PAGE_VISIT => get_string('showtoureachtime', 'tool_usertours'), + ] + ); + $mform->setDefault('showtourwhen', tour::SHOW_TOUR_UNTIL_COMPLETE); + // Configuration. $this->tour->add_config_to_form($mform); diff --git a/admin/tool/usertours/classes/manager.php b/admin/tool/usertours/classes/manager.php index 7ce2915c351..cd9c22ebfee 100644 --- a/admin/tool/usertours/classes/manager.php +++ b/admin/tool/usertours/classes/manager.php @@ -363,6 +363,7 @@ class manager { $tour->set_enabled(!empty($data->enabled)); $tour->set_endtourlabel($data->endtourlabel); $tour->set_display_step_numbers(!empty($data->displaystepnumbers)); + $tour->set_showtourwhen($data->showtourwhen); foreach (configuration::get_defaultable_keys() as $key) { $tour->set_config($key, $data->$key); diff --git a/admin/tool/usertours/classes/tour.php b/admin/tool/usertours/classes/tour.php index e9cb318fae1..61001c5745d 100644 --- a/admin/tool/usertours/classes/tour.php +++ b/admin/tool/usertours/classes/tour.php @@ -52,6 +52,12 @@ class tour { */ const TOUR_REQUESTED_BY_USER = 'tool_usertours_tour_reset_time_'; + /** @var int Whether to show the tour only until it has been marked complete */ + const SHOW_TOUR_UNTIL_COMPLETE = 1; + + /** @var int Whether to show the tour every time a page matches */ + const SHOW_TOUR_ON_EACH_PAGE_VISIT = 2; + /** * @var $id The tour ID. */ @@ -641,6 +647,11 @@ class tour { return false; } + if ($this->get_showtourwhen() === self::SHOW_TOUR_ON_EACH_PAGE_VISIT) { + // The tour should be shown on every page visit. + return true; + } + if ($tourcompletiondate = get_user_preferences(self::TOUR_LAST_COMPLETED_BY_USER . $this->get_id(), null)) { if ($tourresetdate = get_user_preferences(self::TOUR_REQUESTED_BY_USER . $this->get_id(), null)) { if ($tourresetdate >= $tourcompletiondate) { @@ -763,6 +774,7 @@ class tour { */ public function prepare_data_for_form() { $data = $this->to_record(); + $data->showtourwhen = $this->get_showtourwhen(); foreach (configuration::get_defaultable_keys() as $key) { $data->$key = $this->get_config($key, configuration::get_default_value($key)); } @@ -860,4 +872,29 @@ class tour { public function get_display_step_numbers(): bool { return $this->displaystepnumbers; } + + /** + * Set the value for the when to show the tour. + * + * @see self::SHOW_TOUR_UNTIL_COMPLETE + * @see self::SHOW_TOUR_ON_EACH_PAGE_VISIT + * + * @param int $value + * @return self + */ + public function set_showtourwhen(int $value): tour { + return $this->set_config('showtourwhen', $value); + } + + /** + * When to show the tour. + * + * @see self::SHOW_TOUR_UNTIL_COMPLETE + * @see self::SHOW_TOUR_ON_EACH_PAGE_VISIT + * + * @return int + */ + public function get_showtourwhen(): int { + return $this->get_config('showtourwhen', self::SHOW_TOUR_UNTIL_COMPLETE); + } } diff --git a/admin/tool/usertours/lang/en/tool_usertours.php b/admin/tool/usertours/lang/en/tool_usertours.php index 0672417b728..815806de4a9 100644 --- a/admin/tool/usertours/lang/en/tool_usertours.php +++ b/admin/tool/usertours/lang/en/tool_usertours.php @@ -36,6 +36,9 @@ $string['description_help'] = 'The description of a tour may be added as plain t Alternatively, a language string ID may be entered in the format identifier,component (with no brackets or space after the comma).'; $string['displaystepnumbers'] = 'Display step numbers'; $string['displaystepnumbers_help'] = 'Whether to display a step number count e.g. 1/4, 2/4 etc. to indicate the length of the user tour.'; +$string['showtourwhen'] = 'Show tour'; +$string['showtoureachtime'] = 'each time a filter matches it'; +$string['showtouruntilcomplete'] = 'until it has been closed'; $string['confirmstepremovalquestion'] = 'Are you sure that you wish to remove this step?'; $string['confirmstepremovaltitle'] = 'Confirm step removal'; $string['confirmtourremovalquestion'] = 'Are you sure that you wish to remove this tour?'; diff --git a/admin/tool/usertours/tests/behat/tour_prevents_completion.feature b/admin/tool/usertours/tests/behat/tour_prevents_completion.feature new file mode 100644 index 00000000000..0b2e687be9f --- /dev/null +++ b/admin/tool/usertours/tests/behat/tour_prevents_completion.feature @@ -0,0 +1,29 @@ +@tool @tool_usertours +Feature: Prevent yours from being marked as complete + In order to impart key information + As an administrator + I can prevent a user tour from being marked as complete + + Background: + Given I log in as "admin" + And I add a new user tour with: + | Name | First tour | + | Description | My first tour | + | Apply to URL match | FRONTPAGE | + | Tour is enabled | 1 | + | Show with backdrop | 1 | + # 2 = tour::SHOW_TOUR_ON_EACH_PAGE_VISIT + | Show tour | 2 | + And I add steps to the "First tour" tour: + | targettype | Title | id_content | Content type | + | Display in middle of page | Welcome | Welcome tour. | Manual | + + @javascript + Scenario: Ending the tour should not mark it as complete + # Changing the window viewport to mobile so we will have the footer section. + Given I am on site homepage + And I should see "Welcome" + And I press "Got it" + And I should not see "Welcome" + When I am on site homepage + Then I should see "Welcome" diff --git a/admin/tool/usertours/tests/tour_test.php b/admin/tool/usertours/tests/tour_test.php index ab8ba1ded7f..ac34e75015f 100644 --- a/admin/tool/usertours/tests/tour_test.php +++ b/admin/tool/usertours/tests/tour_test.php @@ -98,6 +98,10 @@ class tour_test extends \advanced_testcase { 'config', ['key', 'value'], ], + 'showtourwhen' => [ + 'showtourwhen', + [0], + ], ]; } @@ -598,30 +602,44 @@ class tour_test extends \advanced_testcase { null, null, null, + [], true, ], 'Completed by user before majorupdatetime' => [ $time - DAYSECS, null, $time, + [], true, ], 'Completed by user since majorupdatetime' => [ $time, null, $time - DAYSECS, + [], false, ], 'Requested by user before current completion' => [ $time, $time - DAYSECS, - null, + $time - MINSECS, + [], false, ], 'Requested by user since completion' => [ $time - DAYSECS, $time, + 'null', + [], + true, + ], + 'Tour will show on each load' => [ + $time, + $time - DAYSECS, null, + [ + 'showtourwhen' => tour::SHOW_TOUR_ON_EACH_PAGE_VISIT, + ], true, ], ]; @@ -634,9 +652,16 @@ class tour_test extends \advanced_testcase { * @param mixed $completiondate The user's completion date for this tour * @param mixed $requesteddate The user's last requested date for this tour * @param mixed $updateddate The date this tour was last updated + * @param mixed $config The tour config to apply * @param string $expectation The expected tour key */ - public function test_should_show_for_user($completiondate, $requesteddate, $updateddate, $expectation): void { + public function test_should_show_for_user( + $completiondate, + $requesteddate, + $updateddate, + $config, + $expectation, + ): void { // Uses user preferences so we must be in a user context. $this->resetAfterTest(); $this->setAdminUser(); @@ -644,7 +669,6 @@ class tour_test extends \advanced_testcase { $tour = $this->getMockBuilder(tour::class) ->onlyMethods([ 'get_id', - 'get_config', 'is_enabled', ]) ->getMock(); @@ -652,6 +676,10 @@ class tour_test extends \advanced_testcase { $tour->method('is_enabled') ->willReturn(true); + foreach ($config as $key => $value) { + $tour->set_config($key, $value); + } + $id = rand(1, 100); $tour->method('get_id') ->willReturn($id); @@ -665,9 +693,7 @@ class tour_test extends \advanced_testcase { } if ($updateddate !== null) { - $tour->expects($this->once()) - ->method('get_config') - ->willReturn($updateddate); + $tour->set_config('majorupdatetime', $updateddate); } $this->assertEquals($expectation, $tour->should_show_for_user());