diff --git a/blocks/timeline/tests/behat/block_timeline_search.feature b/blocks/timeline/tests/behat/block_timeline_search.feature index 579779cf787..f25bbd4cf85 100644 --- a/blocks/timeline/tests/behat/block_timeline_search.feature +++ b/blocks/timeline/tests/behat/block_timeline_search.feature @@ -8,25 +8,27 @@ Feature: The timeline block allows users to search for upcoming activities | username | firstname | lastname | email | idnumber | | student1 | Student | 1 | student1@example.com | S1 | And the following "courses" exist: - | fullname | shortname | category | startdate | enddate | - | Course 1 | C1 | 0 | ##1 month ago## | ##15 days ago## | - | Course 2 | C2 | 0 | ##yesterday## | ##tomorrow## | - | Course 3 | C3 | 0 | ##first day of next month## | ##last day of next month## | - | Course 4 | C4 | 0 | ##1 month ago## | ##tomorrow## | - | Course 5 | C5 | 0 | ##first day of last month## | ##last day of next month## | + | fullname | shortname | category | startdate | enddate | + | Course 1 | C1 | 0 | ##1 month ago## | ##15 days ago## | + | Course 2 | C2 | 0 | ##yesterday## | ##tomorrow## | + | Course 3 | C3 | 0 | ##first day of next month## | ##last day of next month## | + | Course 4 | C4 | 0 | ##1 month ago## | ##tomorrow## | + | Course 5 | C5 | 0 | ##first day of last month## | ##last day of next month## | + | Course with advanced name | C6 | 0 | ##first day of last month## | ##last day of next month## | And the following "activities" exist: - | activity | course | idnumber | name | intro | timeopen | timeclose | - | choice | C2 | choice1 | Test choice 1 | Test choice description | ##yesterday## | ##tomorrow## | - | choice | C1 | choice2 | Test choice 2 | Test choice description | ##first day of +5 months## | ##last day of +5 months## | - | choice | C3 | choice3 | Test choice 3 | Test choice description | ##first day of +5 months## | ##last day of +10 months## | - | choice | C2 | choice4 | Test choice 4 | Test choice description | ##first day of +5 months## | ##last day of +15 months## | - | choice | C1 | choice5 | Test choice 5 | Test choice description | ##first day of +5 months## | ##last day of +20 months## | - | choice | C3 | choice6 | Test choice 6 | Test choice description | ##first day of +5 months## | ##last day of +25 months## | - | choice | C4 | choice7 | Test choice 7 | Test choice description | ##first day of +5 months## | ##last day of +5 months## | - | choice | C5 | choice8 | Test choice 8 | Test choice description | ##first day of +5 months## | ##last day of +10 months## | - | feedback | C2 | feedback1 | Test feedback 1 | Test feedback description | ##yesterday## | ##tomorrow## | - | feedback | C1 | feedback2 | Test feedback 2 | Test feedback description | ##first day of +5 months## | ##last day of +5 months## | - | feedback | C3 | feedback3 | Test feedback 3 | Test feedback description | ##first day of +5 months## | ##last day of +10 months## | + | activity | course | idnumber | name | intro | timeopen | timeclose | duedate | + | choice | C2 | choice1 | Test choice 1 | Test choice description | ##yesterday## | ##tomorrow## | | + | choice | C1 | choice2 | Test choice 2 | Test choice description | ##first day of +5 months## | ##last day of +5 months## | | + | choice | C3 | choice3 | Test choice 3 | Test choice description | ##first day of +5 months## | ##last day of +10 months## | | + | choice | C2 | choice4 | Test choice 4 | Test choice description | ##first day of +5 months## | ##last day of +15 months## | | + | choice | C1 | choice5 | Test choice 5 | Test choice description | ##first day of +5 months## | ##last day of +20 months## | | + | choice | C3 | choice6 | Test choice 6 | Test choice description | ##first day of +5 months## | ##last day of +25 months## | | + | choice | C4 | choice7 | Test choice 7 | Test choice description | ##first day of +5 months## | ##last day of +5 months## | | + | choice | C5 | choice8 | Test choice 8 | Test choice description | ##first day of +5 months## | ##last day of +10 months## | | + | feedback | C2 | feedback1 | Test feedback 1 | Test feedback description | ##yesterday## | ##tomorrow## | | + | feedback | C1 | feedback2 | Test feedback 2 | Test feedback description | ##first day of +5 months## | ##last day of +5 months## | | + | feedback | C3 | feedback3 | Test feedback 3 | Test feedback description | ##first day of +5 months## | ##last day of +10 months## | | + | assign | C6 | assign1 | Assign with advanced name | Test assign description | ##yesterday## | | ##tomorrow## | And the following "course enrolments" exist: | user | course | role | | student1 | C1 | student | @@ -34,6 +36,7 @@ Feature: The timeline block allows users to search for upcoming activities | student1 | C3 | student | | student1 | C4 | student | | student1 | C5 | student | + | student1 | C6 | student | Scenario: The search should return no events if I enter the wrong value Given I log in as "student1" @@ -56,6 +59,13 @@ Feature: The timeline block allows users to search for upcoming activities And I should not see "Test feedback 1" in the "Timeline" "block" And I should not see "Test feedback 3" in the "Timeline" "block" + Scenario: Search for Course name - Advanced + Given I log in as "student1" + And I click on "Filter timeline by date" "button" in the "Timeline" "block" + And I click on "All" "link" in the "Timeline" "block" + When I set the field "Search" in the "Timeline" "block" to "Course advanced" + Then I should see "Assign with advanced name" in the "Timeline" "block" + Scenario: Search for Activity name Given I log in as "student1" And I click on "Filter timeline by date" "button" in the "Timeline" "block" @@ -72,6 +82,13 @@ Feature: The timeline block allows users to search for upcoming activities And I should not see "Test feedback 2" in the "Timeline" "block" And I should not see "Test feedback 3" in the "Timeline" "block" + Scenario: Search for Activity name - Advanced + Given I log in as "student1" + And I click on "Filter timeline by date" "button" in the "Timeline" "block" + And I click on "All" "link" in the "Timeline" "block" + When I set the field "Search" in the "Timeline" "block" to "Assign advanced" + Then I should see "Assign with advanced name" in the "Timeline" "block" + Scenario: Search for Activity type Given I log in as "student1" And I click on "Filter timeline by date" "button" in the "Timeline" "block" diff --git a/calendar/classes/local/event/data_access/event_vault.php b/calendar/classes/local/event/data_access/event_vault.php index 4adbeb94299..41c64c60f31 100644 --- a/calendar/classes/local/event/data_access/event_vault.php +++ b/calendar/classes/local/event/data_access/event_vault.php @@ -415,13 +415,18 @@ class event_vault implements event_vault_interface { return null; } - // Course searching. - $whereconditions[] = $DB->sql_like('c.fullname', ':cfullname', false); - $params['cfullname'] = '%' . $DB->sql_like_escape($searchvalue) . '%'; + $parts = preg_split('/\s+/', $searchvalue); + $wherecoursenameconditions = []; + $whereactivitynameconditions = []; + foreach ($parts as $index => $part) { + // Course name searching. + $wherecoursenameconditions[] = $DB->sql_like('c.fullname', ':cfullname' . $index, false); + $params['cfullname'. $index] = '%' . $DB->sql_like_escape($part) . '%'; - // Activity name searching. - $whereconditions[] = $DB->sql_like('e.name', ':eventname', false); - $params['eventname'] = '%' . $DB->sql_like_escape($searchvalue) . '%'; + // Activity name searching. + $whereactivitynameconditions[] = $DB->sql_like('e.name', ':eventname' . $index, false); + $params['eventname'. $index] = '%' . $DB->sql_like_escape($part) . '%'; + } // Activity type searching. $whereconditions[] = $DB->sql_like('e.modulename', ':modulename', false); @@ -440,7 +445,11 @@ class event_vault implements event_vault_interface { $params += $inparams; } - $whereclause = '(' . implode(' OR ', $whereconditions) . ')'; + $whereclause = '('; + $whereclause .= implode(' OR ', $whereconditions); + $whereclause .= ' OR (' . implode(' AND ', $wherecoursenameconditions) . ')'; + $whereclause .= ' OR (' . implode(' AND ', $whereactivitynameconditions) . ')'; + $whereclause .= ')'; return ['where' => $whereclause, 'params' => $params]; } diff --git a/calendar/tests/local_api_test.php b/calendar/tests/local_api_test.php index 85cc4fe2116..0d3e7d1184e 100644 --- a/calendar/tests/local_api_test.php +++ b/calendar/tests/local_api_test.php @@ -28,6 +28,7 @@ require_once(__DIR__ . '/helpers.php'); * @package core_calendar * @copyright 2017 Mark Nelson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \core_calendar\local\api */ class local_api_test extends \advanced_testcase { @@ -286,6 +287,7 @@ class local_api_test extends \advanced_testcase { /** * Test get_calendar_action_events_by_timesort with search feature. + * @covers ::get_action_events_by_timesort */ public function test_get_calendar_action_events_by_timesort_with_search() { // Generate data. @@ -317,6 +319,7 @@ class local_api_test extends \advanced_testcase { $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6])); $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7])); $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8])); + $event9 = create_event(array_merge($params, ['name' => 'Assign with advanced name', 'timesort' => 9])); $this->setUser($user); @@ -325,13 +328,25 @@ class local_api_test extends \advanced_testcase { $this->assertEmpty($result); // Search for event name called 'Event 1'. - $result = \core_calendar\local\api::get_action_events_by_timesort(0, 8, null, 20, false, null, 'Event 1'); + $result = \core_calendar\local\api::get_action_events_by_timesort(0, 10, null, 20, false, null, 'Event 1'); $this->assertCount(1, $result); $this->assertEquals('Event 1', $result[0]->get_name()); + // Search for event name called 'Assign with advanced name'. + $result = \core_calendar\local\api::get_action_events_by_timesort( + 0, 10, null, 20, false, null, 'Assign with advanced name'); + $this->assertCount(1, $result); + $this->assertEquals('Assign with advanced name', $result[0]->get_name()); + + // Search for event name contains 'Assign advanced'. + $result = \core_calendar\local\api::get_action_events_by_timesort( + 0, 10, null, 20, false, null, 'Assign advanced'); + $this->assertCount(1, $result); + $this->assertEquals('Assign with advanced name', $result[0]->get_name()); + // Search for activity type called 'assign'. - $result = \core_calendar\local\api::get_action_events_by_timesort(0, 8, null, 20, false, null, 'assign'); - $this->assertCount(8, $result); + $result = \core_calendar\local\api::get_action_events_by_timesort(0, 10, null, 20, false, null, 'assign'); + $this->assertCount(9, $result); $this->assertEquals('Event 1', $result[0]->get_name()); $this->assertEquals('Event 2', $result[1]->get_name()); $this->assertEquals('Event 3', $result[2]->get_name()); @@ -340,6 +355,7 @@ class local_api_test extends \advanced_testcase { $this->assertEquals('Event 6', $result[5]->get_name()); $this->assertEquals('Event 7', $result[6]->get_name()); $this->assertEquals('Event 8', $result[7]->get_name()); + $this->assertEquals('Assign with advanced name', $result[8]->get_name()); } /** @@ -696,6 +712,78 @@ class local_api_test extends \advanced_testcase { $this->assertEquals('Event 6', $result[$course3->id][0]->get_name()); } + /** + * Test get_action_events_by_courses with search feature. + * @covers ::get_action_events_by_courses + */ + public function test_get_action_events_by_courses_with_search() { + // Generate data. + $user = $this->getDataGenerator()->create_user(); + $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course with advanced name']); + $course2 = $this->getDataGenerator()->create_course(['fullname' => 'Another name']); + $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); + $moduleinstance1 = $generator->create_instance(['course' => $course1->id]); + $moduleinstance2 = $generator->create_instance(['course' => $course2->id]); + + $this->getDataGenerator()->enrol_user($user->id, $course1->id); + $this->getDataGenerator()->enrol_user($user->id, $course2->id); + $this->resetAfterTest(true); + $this->setUser($user); + + $params = [ + 'type' => CALENDAR_EVENT_TYPE_ACTION, + 'modulename' => 'assign', + 'instance' => $moduleinstance1->id, + 'userid' => $user->id, + 'courseid' => $course1->id, + 'eventtype' => 'user', + 'repeats' => 0, + 'timestart' => 1, + ]; + + $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1])); + $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2])); + + $params['courseid'] = $course2->id; + $params['instance'] = $moduleinstance2->id; + $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3])); + $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4])); + $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5])); + + // No result found for fake search. + $result = \core_calendar\local\api::get_action_events_by_courses( + [$course1, $course2], 1, null, '6', 'Fake search'); + $this->assertEmpty($result[$course1->id]); + $this->assertEmpty($result[$course2->id]); + + // Search for course name called 'Course with advanced name'. + $result = \core_calendar\local\api::get_action_events_by_courses( + [$course1, $course2], 1, null, '6', 'Course with advanced name'); + $this->assertNotEmpty($result[$course1->id]); + $this->assertEmpty($result[$course2->id]); + $this->assertEquals('Event 1', $result[$course1->id][0]->get_name()); + $this->assertEquals('Event 2', $result[$course1->id][1]->get_name()); + + // Search for course name contains 'Course advanced'. + $result = \core_calendar\local\api::get_action_events_by_courses( + [$course1, $course2], 1, null, '6', 'Course advanced'); + $this->assertNotEmpty($result[$course1->id]); + $this->assertEmpty($result[$course2->id]); + $this->assertEquals('Event 1', $result[$course1->id][0]->get_name()); + $this->assertEquals('Event 2', $result[$course1->id][1]->get_name()); + + // Search for course name contains 'name'. + $result = \core_calendar\local\api::get_action_events_by_courses( + [$course1, $course2], 1, null, '6', 'name'); + $this->assertNotEmpty($result[$course1->id]); + $this->assertNotEmpty($result[$course2->id]); + $this->assertEquals('Event 1', $result[$course1->id][0]->get_name()); + $this->assertEquals('Event 2', $result[$course1->id][1]->get_name()); + $this->assertEquals('Event 3', $result[$course2->id][0]->get_name()); + $this->assertEquals('Event 4', $result[$course2->id][1]->get_name()); + $this->assertEquals('Event 5', $result[$course2->id][2]->get_name()); + } + /** * Test that the get_legacy_events() function only returns activity events that are enabled. */