From c242e3f4dd2441b888090d7bead5b81fcbabccd6 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Mon, 19 Oct 2015 14:39:56 +0800 Subject: [PATCH] MDL-49231 mod_glossary: External function get_entries_to_approve --- mod/glossary/classes/external.php | 90 +++++++++++++++++++++++ mod/glossary/lib.php | 43 +++++++++++ mod/glossary/tests/external_test.php | 106 +++++++++++++++++++++++++++ 3 files changed, 239 insertions(+) diff --git a/mod/glossary/classes/external.php b/mod/glossary/classes/external.php index 33c96b57219..d56eb48f662 100644 --- a/mod/glossary/classes/external.php +++ b/mod/glossary/classes/external.php @@ -1283,6 +1283,96 @@ class mod_glossary_external extends external_api { )); } + /** + * Returns the description of the external function parameters. + * + * @return external_function_parameters + * @since Moodle 3.1 + */ + public static function get_entries_to_approve_parameters() { + return new external_function_parameters(array( + 'id' => new external_value(PARAM_INT, 'Glossary entry ID'), + 'letter' => new external_value(PARAM_ALPHA, 'A letter, or either keywords: \'ALL\' or \'SPECIAL\'.'), + 'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT, + 'CONCEPT'), + 'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'), + 'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0), + 'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20), + 'options' => new external_single_structure(array(), 'An array of options', VALUE_DEFAULT, array()) + )); + } + + /** + * Browse a glossary entries using a term matching the concept or alias. + * + * @param int $id The glossary ID. + * @param string $letter A letter, or a special keyword. + * @param string $order The way to order the records. + * @param string $sort The direction of the order. + * @param int $from Start returning records from here. + * @param int $limit Number of records to return. + * @param array $options Array of options. + * @return array of warnings and status result + * @since Moodle 3.1 + * @throws moodle_exception + */ + public static function get_entries_to_approve($id, $letter, $order = 'CONCEPT', $sort = 'ASC', $from = 0, $limit = 20) { + global $DB, $USER; + + $params = self::validate_parameters(self::get_entries_to_approve_parameters(), array( + 'id' => $id, + 'letter' => $letter, + 'order' => $order, + 'sort' => $sort, + 'from' => $from, + 'limit' => $limit + )); + $id = $params['id']; + $letter = $params['letter']; + $order = $params['order']; + $sort = $params['sort']; + $from = $params['from']; + $limit = $params['limit']; + $warnings = array(); + + // Get and validate the glossary. + list($glossary, $context) = self::validate_glossary($id); + + // Check the permissions. + require_capability('mod/glossary:approve', $context); + + // Fetching the entries. + $entries = array(); + list($records, $count) = glossary_get_entries_to_approve($glossary, $context, $letter, $order, $sort, $from, $limit); + foreach ($records as $key => $record) { + self::fill_entry_details($record, $context); + $entries[] = $record; + } + $records->close(); + + return array( + 'count' => $count, + 'entries' => $entries, + 'warnings' => $warnings + ); + } + + /** + * Returns the description of the external function return value. + * + * @return external_description + * @since Moodle 3.1 + */ + public static function get_entries_to_approve_returns() { + return new external_single_structure(array( + 'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'), + 'entries' => new external_multiple_structure( + self::get_entry_return_structure() + ), + 'warnings' => new external_warnings() + )); + } + /** * Returns the description of the external function parameters. * diff --git a/mod/glossary/lib.php b/mod/glossary/lib.php index 2bafd1ccf36..508db114fd5 100644 --- a/mod/glossary/lib.php +++ b/mod/glossary/lib.php @@ -3735,6 +3735,49 @@ function glossary_get_entries_by_term($glossary, $context, $term, $from, $limit, return array($entries, $count); } +/** + * Returns the entries to be approved. + * + * @param object $glossary The glossary. + * @param context $context The context of the glossary. + * @param string $letter The letter, or ALL, or SPECIAL. + * @param string $order The mode of ordering: CONCEPT, CREATION or UPDATE. + * @param string $sort The direction of the ordering: ASC or DESC. + * @param int $from Fetch records from. + * @param int $limit Number of records to fetch. + * @return array The first element being the recordset, the second the number of entries. + * @since Moodle 3.1 + */ +function glossary_get_entries_to_approve($glossary, $context, $letter, $order, $sort, $from, $limit) { + + $qb = new mod_glossary_entry_query_builder($glossary); + if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) { + $qb->filter_by_concept_letter($letter); + } + if ($letter == 'SPECIAL') { + $qb->filter_by_concept_non_letter(); + } + + $qb->add_field('*', 'entries'); + $qb->join_user(); + $qb->add_user_fields(); + $qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ONLY); + if ($order == 'CREATION') { + $qb->order_by('timecreated', 'entries', $sort); + } else if ($order == 'UPDATE') { + $qb->order_by('timemodified', 'entries', $sort); + } else { + $qb->order_by('concept', 'entries', $sort); + } + $qb->limit($from, $limit); + + // Fetching the entries. + $count = $qb->count_records(); + $entries = $qb->get_recordset(); + + return array($entries, $count); +} + /** * Fetch an entry. * diff --git a/mod/glossary/tests/external_test.php b/mod/glossary/tests/external_test.php index e09b6022049..c8b3b2b7a07 100644 --- a/mod/glossary/tests/external_test.php +++ b/mod/glossary/tests/external_test.php @@ -927,6 +927,112 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase { $this->assertEquals($e2->id, $return['entries'][0]['id']); } + public function test_get_entries_to_approve() { + $this->resetAfterTest(true); + + // Generate all the things. + $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $c1 = $this->getDataGenerator()->create_course(); + $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id)); + $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id)); + $u1 = $this->getDataGenerator()->create_user(); + $ctx = context_module::instance($g1->cmid); + $this->getDataGenerator()->enrol_user($u1->id, $c1->id); + + $e1a = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Bob', 'userid' => $u1->id, + 'timecreated' => time() + 3600)); + $e1b = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Jane', 'userid' => $u1->id, 'timecreated' => 1)); + $e1c = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Alice', 'userid' => $u1->id, 'timemodified' => 1)); + $e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id, + 'timemodified' => time() + 3600)); + $e1e = $gg->create_content($g1, array('approved' => 1, 'concept' => '1-day', 'userid' => $u1->id)); + $e2a = $gg->create_content($g2); + + $this->setAdminUser(true); + + // Simple listing. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 20); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(4, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1d->id, $return['entries'][0]['id']); + $this->assertEquals($e1c->id, $return['entries'][1]['id']); + $this->assertEquals($e1a->id, $return['entries'][2]['id']); + $this->assertEquals($e1b->id, $return['entries'][3]['id']); + + // Revert ordering of concept. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'DESC', 0, 20); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(4, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1b->id, $return['entries'][0]['id']); + $this->assertEquals($e1a->id, $return['entries'][1]['id']); + $this->assertEquals($e1c->id, $return['entries'][2]['id']); + $this->assertEquals($e1d->id, $return['entries'][3]['id']); + + // Filtering by letter. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'a', 'CONCEPT', 'ASC', 0, 20); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(1, $return['count']); + $this->assertEquals($e1c->id, $return['entries'][0]['id']); + + // Filtering by special. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'SPECIAL', 'CONCEPT', 'ASC', 0, 20); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(1, $return['count']); + $this->assertEquals($e1d->id, $return['entries'][0]['id']); + + // Pagination. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 2); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(2, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1d->id, $return['entries'][0]['id']); + $this->assertEquals($e1c->id, $return['entries'][1]['id']); + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 1, 2); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(2, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1c->id, $return['entries'][0]['id']); + $this->assertEquals($e1a->id, $return['entries'][1]['id']); + + // Ordering by creation date. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CREATION', 'ASC', 0, 1); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1b->id, $return['entries'][0]['id']); + + // Ordering by creation date desc. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CREATION', 'DESC', 0, 1); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1a->id, $return['entries'][0]['id']); + + // Ordering by update date. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'UPDATE', 'ASC', 0, 1); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1c->id, $return['entries'][0]['id']); + + // Ordering by update date desc. + $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'UPDATE', 'DESC', 0, 1); + $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return); + $this->assertCount(1, $return['entries']); + $this->assertEquals(4, $return['count']); + $this->assertEquals($e1d->id, $return['entries'][0]['id']); + + // Permissions are checked. + $this->setUser($u1); + $this->setExpectedException('required_capability_exception'); + mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 1); + $this->fail('Do not test anything else after this.'); + } + public function test_get_entry_by_id() { $this->resetAfterTest(true); -- 2.43.0