From e8ad99ab91f6f127b176dd28f61f3bfe264951cd Mon Sep 17 00:00:00 2001 From: Juan Leyva Date: Mon, 28 Sep 2015 14:04:04 +0200 Subject: [PATCH] MDL-51568 self_enrol: New Web Service enrol_self_enrol_user --- enrol/self/db/services.php | 8 ++ enrol/self/externallib.php | 154 ++++++++++++++++++++++++++ enrol/self/locallib.php | 40 +++++-- enrol/self/tests/externallib_test.php | 143 ++++++++++++++++++++++++ enrol/self/tests/self_test.php | 37 +++++++ enrol/self/version.php | 2 +- lib/db/services.php | 1 + version.php | 2 +- 8 files changed, 373 insertions(+), 14 deletions(-) diff --git a/enrol/self/db/services.php b/enrol/self/db/services.php index dd50355b61c..506defdd13b 100644 --- a/enrol/self/db/services.php +++ b/enrol/self/db/services.php @@ -30,5 +30,13 @@ $functions = array( 'classpath' => 'enrol/self/externallib.php', 'description' => 'self enrolment instance information.', 'type' => 'read' + ), + + 'enrol_self_enrol_user' => array( + 'classname' => 'enrol_self_external', + 'methodname' => 'enrol_user', + 'classpath' => 'enrol/self/externallib.php', + 'description' => 'Self enrol the current user in the given course.', + 'type' => 'write' ) ); diff --git a/enrol/self/externallib.php b/enrol/self/externallib.php index 4451087e439..ad61b0ce075 100644 --- a/enrol/self/externallib.php +++ b/enrol/self/externallib.php @@ -97,4 +97,158 @@ class enrol_self_external extends external_api { ) ); } + + /** + * Returns description of method parameters + * + * @return external_function_parameters + * @since Moodle 3.0 + */ + public static function enrol_user_parameters() { + return new external_function_parameters( + array( + 'courseid' => new external_value(PARAM_INT, 'Id of the course'), + 'password' => new external_value(PARAM_RAW, 'Enrolment key', VALUE_DEFAULT, ''), + 'instanceid' => new external_value(PARAM_INT, 'Instance id of self enrolment plugin.', VALUE_DEFAULT, 0) + ) + ); + } + + /** + * Self enrol the current user in the given course. + * + * @param int $courseid id of course + * @param string $password enrolment key + * @param int $instanceid instance id of self enrolment plugin + * @return array of warnings and status result + * @since Moodle 3.0 + * @throws moodle_exception + */ + public static function enrol_user($courseid, $password = '', $instanceid = 0) { + global $CFG; + + require_once($CFG->libdir . '/enrollib.php'); + + $params = self::validate_parameters(self::enrol_user_parameters(), + array( + 'courseid' => $courseid, + 'password' => $password, + 'instanceid' => $instanceid + )); + + $warnings = array(); + + $course = get_course($params['courseid']); + $context = context_course::instance($course->id); + // Note that we can't use validate_context because the user is not enrolled in the course. + require_login(null, false, null, false, true); + + if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) { + throw new moodle_exception('coursehidden'); + } + + // Retrieve the self enrolment plugin. + $enrol = enrol_get_plugin('self'); + if (empty($enrol)) { + throw new moodle_exception('canntenrol', 'enrol_self'); + } + + // We can expect multiple self-enrolment instances. + $instances = array(); + $enrolinstances = enrol_get_instances($course->id, true); + foreach ($enrolinstances as $courseenrolinstance) { + if ($courseenrolinstance->enrol == "self") { + // Instance specified. + if (!empty($params['instanceid'])) { + if ($courseenrolinstance->id == $params['instanceid']) { + $instances[] = $courseenrolinstance; + break; + } + } else { + $instances[] = $courseenrolinstance; + } + + } + } + if (empty($instances)) { + throw new moodle_exception('canntenrol', 'enrol_self'); + } + + // Try to enrol the user in the instance/s. + $enrolled = false; + foreach ($instances as $instance) { + $enrolstatus = $enrol->can_self_enrol($instance); + if ($enrolstatus === true) { + if ($instance->password and $params['password'] !== $instance->password) { + + // Check if we are using group enrolment keys. + if ($instance->customint1) { + require_once($CFG->dirroot . "/enrol/self/locallib.php"); + + if (!enrol_self_check_group_enrolment_key($course->id, $params['password'])) { + $warnings[] = array( + 'item' => 'instance', + 'itemid' => $instance->id, + 'warningcode' => '2', + 'message' => get_string('passwordinvalid', 'enrol_self') + ); + continue; + } + } else { + if ($enrol->get_config('showhint')) { + $hint = core_text::substr($instance->password, 0, 1); + $warnings[] = array( + 'item' => 'instance', + 'itemid' => $instance->id, + 'warningcode' => '3', + 'message' => s(get_string('passwordinvalidhint', 'enrol_self', $hint)) // message is PARAM_TEXT. + ); + continue; + } else { + $warnings[] = array( + 'item' => 'instance', + 'itemid' => $instance->id, + 'warningcode' => '4', + 'message' => get_string('passwordinvalid', 'enrol_self') + ); + continue; + } + } + } + + // Do the enrolment. + $data = array('enrolpassword' => $params['password']); + $enrol->enrol_self($instance, (object) $data); + $enrolled = true; + break; + } else { + $warnings[] = array( + 'item' => 'instance', + 'itemid' => $instance->id, + 'warningcode' => '1', + 'message' => $enrolstatus + ); + } + } + + $result = array(); + $result['status'] = $enrolled; + $result['warnings'] = $warnings; + return $result; + } + + /** + * Returns description of method result value + * + * @return external_description + * @since Moodle 3.0 + */ + public static function enrol_user_returns() { + return new external_single_structure( + array( + 'status' => new external_value(PARAM_BOOL, 'status: true if the user is enrolled, false otherwise'), + 'warnings' => new external_warnings() + ) + ); + } } diff --git a/enrol/self/locallib.php b/enrol/self/locallib.php index 226555df94d..a60224e1acc 100644 --- a/enrol/self/locallib.php +++ b/enrol/self/locallib.php @@ -26,6 +26,32 @@ defined('MOODLE_INTERNAL') || die(); require_once("$CFG->libdir/formslib.php"); +/** + * Check if the given password match a group enrolment key in the specified course. + * + * @param int $courseid course id + * @param string $enrolpassword enrolment password + * @return bool True if match + * @since Moodle 3.0 + */ +function enrol_self_check_group_enrolment_key($courseid, $enrolpassword) { + global $DB; + + $found = false; + $groups = $DB->get_records('groups', array('courseid' => $courseid), 'id ASC', 'id, enrolmentkey'); + + foreach ($groups as $group) { + if (empty($group->enrolmentkey)) { + continue; + } + if ($group->enrolmentkey === $enrolpassword) { + $found = true; + break; + } + } + return $found; +} + class enrol_self_enrol_form extends moodleform { protected $instance; protected $toomany = false; @@ -103,18 +129,8 @@ class enrol_self_enrol_form extends moodleform { if ($instance->password) { if ($data['enrolpassword'] !== $instance->password) { if ($instance->customint1) { - $groups = $DB->get_records('groups', array('courseid'=>$instance->courseid), 'id ASC', 'id, enrolmentkey'); - $found = false; - foreach ($groups as $group) { - if (empty($group->enrolmentkey)) { - continue; - } - if ($group->enrolmentkey === $data['enrolpassword']) { - $found = true; - break; - } - } - if (!$found) { + // Check group enrolment key. + if (!enrol_self_check_group_enrolment_key($instance->courseid, $data['enrolpassword'])) { // We can not hint because there are probably multiple passwords. $errors['enrolpassword'] = get_string('passwordinvalid', 'enrol_self'); } diff --git a/enrol/self/tests/externallib_test.php b/enrol/self/tests/externallib_test.php index d4abbe2c62f..74b1cbe9c3d 100644 --- a/enrol/self/tests/externallib_test.php +++ b/enrol/self/tests/externallib_test.php @@ -96,4 +96,147 @@ class enrol_self_external_testcase extends externallib_advanced_testcase { $this->assertTrue($instanceinfo3['status']); $this->assertEquals(get_string('password', 'enrol_self'), $instanceinfo3['enrolpassword']); } + + /** + * Test enrol_user + */ + public function test_enrol_user() { + global $DB; + + self::resetAfterTest(true); + + $user = self::getDataGenerator()->create_user(); + self::setUser($user); + + $course1 = self::getDataGenerator()->create_course(); + $course2 = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $context1 = context_course::instance($course1->id); + $context2 = context_course::instance($course2->id); + + $selfplugin = enrol_get_plugin('self'); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $instance1id = $selfplugin->add_instance($course1, array('status' => ENROL_INSTANCE_ENABLED, + 'name' => 'Test instance 1', + 'customint6' => 1, + 'roleid' => $studentrole->id)); + $instance2id = $selfplugin->add_instance($course2, array('status' => ENROL_INSTANCE_DISABLED, + 'customint6' => 1, + 'name' => 'Test instance 2', + 'roleid' => $studentrole->id)); + $instance1 = $DB->get_record('enrol', array('id' => $instance1id), '*', MUST_EXIST); + $instance2 = $DB->get_record('enrol', array('id' => $instance2id), '*', MUST_EXIST); + + self::setUser($user1); + + // Self enrol me. + $result = enrol_self_external::enrol_user($course1->id); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + + self::assertTrue($result['status']); + self::assertEquals(1, $DB->count_records('user_enrolments', array('enrolid' => $instance1->id))); + self::assertTrue(is_enrolled($context1, $user1)); + + // Add password. + $instance2->password = 'abcdef'; + $DB->update_record('enrol', $instance2); + + // Try instance not enabled. + try { + enrol_self_external::enrol_user($course2->id); + } catch (moodle_exception $e) { + self::assertEquals('canntenrol', $e->errorcode); + } + + // Enable the instance. + $selfplugin->update_status($instance2, ENROL_INSTANCE_ENABLED); + + // Try not passing a key. + $result = enrol_self_external::enrol_user($course2->id); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertFalse($result['status']); + self::assertCount(1, $result['warnings']); + self::assertEquals('4', $result['warnings'][0]['warningcode']); + + // Try passing an invalid key. + $result = enrol_self_external::enrol_user($course2->id, 'invalidkey'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertFalse($result['status']); + self::assertCount(1, $result['warnings']); + self::assertEquals('4', $result['warnings'][0]['warningcode']); + + // Try passing an invalid key with hint. + $selfplugin->set_config('showhint', true); + $result = enrol_self_external::enrol_user($course2->id, 'invalidkey'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertFalse($result['status']); + self::assertCount(1, $result['warnings']); + self::assertEquals('3', $result['warnings'][0]['warningcode']); + + // Everything correct, now. + $result = enrol_self_external::enrol_user($course2->id, 'abcdef'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + + self::assertTrue($result['status']); + self::assertEquals(1, $DB->count_records('user_enrolments', array('enrolid' => $instance2->id))); + self::assertTrue(is_enrolled($context2, $user1)); + + // Try group password now, other user. + $instance2->customint1 = 1; + $instance2->password = 'zyx'; + $DB->update_record('enrol', $instance2); + + $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course2->id)); + $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'enrolmentkey' => 'zyx')); + + self::setUser($user2); + // Try passing and invalid key for group. + $result = enrol_self_external::enrol_user($course2->id, 'invalidkey'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertFalse($result['status']); + self::assertCount(1, $result['warnings']); + self::assertEquals('2', $result['warnings'][0]['warningcode']); + + // Now, everything ok. + $result = enrol_self_external::enrol_user($course2->id, 'zyx'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + + self::assertTrue($result['status']); + self::assertEquals(2, $DB->count_records('user_enrolments', array('enrolid' => $instance2->id))); + self::assertTrue(is_enrolled($context2, $user2)); + + // Try multiple instances now, multiple errors. + $instance3id = $selfplugin->add_instance($course2, array('status' => ENROL_INSTANCE_ENABLED, + 'customint6' => 1, + 'name' => 'Test instance 2', + 'roleid' => $studentrole->id)); + $instance3 = $DB->get_record('enrol', array('id' => $instance3id), '*', MUST_EXIST); + $instance3->password = 'abcdef'; + $DB->update_record('enrol', $instance3); + + self::setUser($user3); + $result = enrol_self_external::enrol_user($course2->id, 'invalidkey'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertFalse($result['status']); + self::assertCount(2, $result['warnings']); + + // Now, everything ok. + $result = enrol_self_external::enrol_user($course2->id, 'zyx'); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertTrue($result['status']); + self::assertTrue(is_enrolled($context2, $user3)); + + // Now test passing an instance id. + self::setUser($user4); + $result = enrol_self_external::enrol_user($course2->id, 'abcdef', $instance3id); + $result = external_api::clean_returnvalue(enrol_self_external::enrol_user_returns(), $result); + self::assertTrue($result['status']); + self::assertTrue(is_enrolled($context2, $user3)); + self::assertCount(0, $result['warnings']); + self::assertEquals(1, $DB->count_records('user_enrolments', array('enrolid' => $instance3->id))); + } } diff --git a/enrol/self/tests/self_test.php b/enrol/self/tests/self_test.php index b4250c0ef04..b6956003073 100644 --- a/enrol/self/tests/self_test.php +++ b/enrol/self/tests/self_test.php @@ -614,4 +614,41 @@ class enrol_self_testcase extends advanced_testcase { $this->setUser($user1); $this->assertSame($expectederrorstring, $selfplugin->can_self_enrol($instance1, true)); } + + /** + * Test enrol_self_check_group_enrolment_key + */ + public function test_enrol_self_check_group_enrolment_key() { + global $DB; + self::resetAfterTest(true); + + // Test in course with groups. + $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); + + $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); + $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'enrolmentkey' => 'thepassword')); + + $result = enrol_self_check_group_enrolment_key($course->id, 'invalidpassword'); + $this->assertFalse($result); + + $result = enrol_self_check_group_enrolment_key($course->id, 'thepassword'); + $this->assertTrue($result); + + // Test disabling group options. + $course->groupmode = NOGROUPS; + $course->groupmodeforce = 0; + $DB->update_record('course', $course); + + $result = enrol_self_check_group_enrolment_key($course->id, 'invalidpassword'); + $this->assertFalse($result); + + $result = enrol_self_check_group_enrolment_key($course->id, 'thepassword'); + $this->assertTrue($result); + + // Test without groups. + $othercourse = self::getDataGenerator()->create_course(); + $result = enrol_self_check_group_enrolment_key($othercourse->id, 'thepassword'); + $this->assertFalse($result); + + } } diff --git a/enrol/self/version.php b/enrol/self/version.php index 5e89b6c4ba5..e5933e08515 100644 --- a/enrol/self/version.php +++ b/enrol/self/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX) +$plugin->version = 2015051101; // The current plugin version (Date: YYYYMMDDXX) $plugin->requires = 2015050500; // Requires this Moodle version $plugin->component = 'enrol_self'; // Full name of the plugin (used for diagnostics) $plugin->cron = 600; diff --git a/lib/db/services.php b/lib/db/services.php index 6451e6316da..effb6565490 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1158,6 +1158,7 @@ $services = array( 'core_calendar_get_calendar_events', 'core_enrol_get_users_courses', 'core_enrol_get_enrolled_users', + 'enrol_self_enrol_user', 'core_user_get_users_by_id', 'core_webservice_get_site_info', 'core_notes_create_notes', diff --git a/version.php b/version.php index f810c839d18..c78bc6a6330 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2015100800.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2015100800.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. -- 2.43.0