diff --git a/enrol/externallib.php b/enrol/externallib.php index 593541e131a..89cff4856fa 100644 --- a/enrol/externallib.php +++ b/enrol/externallib.php @@ -1020,6 +1020,70 @@ class core_enrol_external extends external_api { ); } + /** + * Returns description of submit_user_enrolment_form parameters. + * + * @return external_function_parameters. + */ + public static function submit_user_enrolment_form_parameters() { + return new external_function_parameters([ + 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'), + ]); + } + + /** + * External function that handles the user enrolment form submission. + * + * @param string $formdata The user enrolment form data in s URI encoded param string + * @return array An array consisting of the processing result and error flag, if available + */ + public static function submit_user_enrolment_form($formdata) { + global $CFG, $DB, $PAGE; + + // Parameter validation. + $params = self::validate_parameters(self::submit_user_enrolment_form_parameters(), ['formdata' => $formdata]); + + $data = []; + parse_str($params['formdata'], $data); + + $userenrolment = $DB->get_record('user_enrolments', ['id' => $data['ue']], '*', MUST_EXIST); + $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST); + $plugin = enrol_get_plugin($instance->enrol); + $course = get_course($instance->courseid); + $context = context_course::instance($course->id); + self::validate_context($context); + + require_once("$CFG->dirroot/enrol/editenrolment_form.php"); + $customformdata = [ + 'ue' => $userenrolment, + 'modal' => true, + 'enrolinstancename' => $plugin->get_instance_name($instance) + ]; + $mform = new enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $data); + + if ($validateddata = $mform->get_data()) { + require_once($CFG->dirroot . '/enrol/locallib.php'); + $manager = new course_enrolment_manager($PAGE, $course); + $result = $manager->edit_enrolment($userenrolment, $validateddata); + + return ['result' => $result]; + } else { + return ['result' => false, 'validationerror' => true]; + } + } + + /** + * Returns description of submit_user_enrolment_form() result value + * + * @return external_description + */ + public static function submit_user_enrolment_form_returns() { + return new external_single_structure([ + 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'), + 'validationerror' => new external_value(PARAM_BOOL, 'Indicates invalid form data', VALUE_DEFAULT, false), + ]); + } + /** * Returns description of unenrol_user_enrolment() parameters * diff --git a/enrol/tests/externallib_test.php b/enrol/tests/externallib_test.php index da07c87ab97..ee4ca4bba3b 100644 --- a/enrol/tests/externallib_test.php +++ b/enrol/tests/externallib_test.php @@ -958,6 +958,154 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase { $this->assertEquals(ENROL_USER_SUSPENDED, $ue->status); } + /** + * dataProvider for test_submit_user_enrolment_form(). + */ + public function submit_user_enrolment_form_provider() { + $now = new DateTime(); + + $nextmonth = clone($now); + $nextmonth->add(new DateInterval('P1M')); + + return [ + 'Invalid data' => [ + 'customdata' => [ + 'status' => ENROL_USER_ACTIVE, + 'timestart' => [ + 'day' => $now->format('j'), + 'month' => $now->format('n'), + 'year' => $now->format('Y'), + 'hour' => $now->format('G'), + 'minute' => 0, + 'enabled' => 1, + ], + 'timeend' => [ + 'day' => $now->format('j'), + 'month' => $now->format('n'), + 'year' => $now->format('Y'), + 'hour' => $now->format('G'), + 'minute' => 0, + 'enabled' => 1, + ], + ], + 'expectedresult' => false, + 'validationerror' => true + ], + 'Valid data' => [ + 'customdata' => [ + 'status' => ENROL_USER_ACTIVE, + 'timestart' => [ + 'day' => $now->format('j'), + 'month' => $now->format('n'), + 'year' => $now->format('Y'), + 'hour' => $now->format('G'), + 'minute' => 0, + 'enabled' => 1, + ], + 'timeend' => [ + 'day' => $nextmonth->format('j'), + 'month' => $nextmonth->format('n'), + 'year' => $nextmonth->format('Y'), + 'hour' => $nextmonth->format('G'), + 'minute' => 0, + 'enabled' => 1, + ], + ], + 'expectedresult' => true, + 'validationerror' => false + ], + 'Suspend user' => [ + 'customdata' => [ + 'status' => ENROL_USER_SUSPENDED, + ], + 'expectedresult' => true, + 'validationerror' => false + ], + ]; + } + + /** + * @param array $customdata The data we are providing to the webservice. + * @param bool $expectedresult The result we are expecting to receive from the webservice. + * @param bool $validationerror The validationerror we are expecting to receive from the webservice. + * @dataProvider submit_user_enrolment_form_provider + */ + public function test_submit_user_enrolment_form($customdata, $expectedresult, $validationerror) { + global $CFG, $DB; + + $this->resetAfterTest(true); + $datagen = $this->getDataGenerator(); + + /** @var enrol_manual_plugin $manualplugin */ + $manualplugin = enrol_get_plugin('manual'); + + $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); + $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); + $course = $datagen->create_course(); + $user = $datagen->create_user(); + $teacher = $datagen->create_user(); + + $instanceid = null; + $instances = enrol_get_instances($course->id, true); + foreach ($instances as $inst) { + if ($inst->enrol == 'manual') { + $instanceid = (int)$inst->id; + break; + } + } + if (empty($instanceid)) { + $instanceid = $manualplugin->add_default_instance($course); + if (empty($instanceid)) { + $instanceid = $manualplugin->add_instance($course); + } + } + $this->assertNotNull($instanceid); + + $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); + $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); + $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); + $ueid = (int) $DB->get_field( + 'user_enrolments', + 'id', + ['enrolid' => $instance->id, 'userid' => $user->id], + MUST_EXIST + ); + + // Login as teacher. + $teacher->ignoresesskey = true; + $this->setUser($teacher); + + $formdata = [ + 'ue' => $ueid, + 'ifilter' => 0, + 'status' => null, + 'timestart' => null, + 'timeend' => null, + ]; + + $formdata = array_merge($formdata, $customdata); + + require_once("$CFG->dirroot/enrol/editenrolment_form.php"); + $formdata = enrol_user_enrolment_form::mock_generate_submit_keys($formdata); + + $querystring = http_build_query($formdata, '', '&'); + + $result = external_api::clean_returnvalue( + core_enrol_external::submit_user_enrolment_form_returns(), + core_enrol_external::submit_user_enrolment_form($querystring) + ); + + $this->assertEquals( + ['result' => $expectedresult, 'validationerror' => $validationerror], + $result, + '', 0.0, 10, true); + + if (!empty($result['result'])) { + $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); + $this->assertEquals($formdata['status'], $ue->status); + } + } + /** * Test for core_enrol_external::unenrol_user_enrolment(). */ diff --git a/lib/db/services.php b/lib/db/services.php index 708f2ccdb80..397c45771ec 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -660,6 +660,14 @@ $functions = array( 'type' => 'write', 'ajax' => true, ), + 'core_enrol_submit_user_enrolment_form' => array( + 'classname' => 'core_enrol_external', + 'methodname' => 'submit_user_enrolment_form', + 'classpath' => 'enrol/externallib.php', + 'description' => 'Submit form data for enrolment form', + 'type' => 'write', + 'ajax' => true, + ), 'core_enrol_unenrol_user_enrolment' => array( 'classname' => 'core_enrol_external', 'methodname' => 'unenrol_user_enrolment', diff --git a/user/amd/build/status_field.min.js b/user/amd/build/status_field.min.js index a26e99fbe9d..8d8d633fb18 100644 --- a/user/amd/build/status_field.min.js +++ b/user/amd/build/status_field.min.js @@ -1 +1 @@ -define(["core/templates","jquery","core/str","core/config","core/notification","core/modal_factory","core/modal_events","core/fragment","core/ajax"],function(a,b,c,d,e,f,g,h,i){var j={EDIT_ENROLMENT:'[data-action="editenrolment"]',SHOW_DETAILS:'[data-action="showdetails"]',UNENROL:'[data-action="unenrol"]'},k=function(a){this.contextid=a.contextid,this.courseid=a.courseid,this.bindEditEnrol(),this.bindUnenrol(),this.bindStatusDetails()};return k.prototype.courseid=0,k.prototype.bindEditEnrol=function(){var a=this;b(j.EDIT_ENROLMENT).click(function(d){d.preventDefault();var h=b(this),i=h.parent(),j=i.data("fullname"),k=h.attr("rel");b.when(c.get_string("edituserenrolment","enrol",j)).then(function(a){return f.create({large:!0,title:a,type:f.types.SAVE_CANCEL})}).done(function(b){b.getRoot().on(g.save,function(c){c.preventDefault(),a.submitEditFormAjax(b)}),b.getRoot().on(g.hidden,function(){b.destroy()}),b.setBody(a.getBody(k)),b.show()}).fail(e.exception)})},k.prototype.bindUnenrol=function(){var a=this;b(j.UNENROL).click(function(d){d.preventDefault();var h=b(this),i=h.parent(),j=[{key:"unenrol",component:"enrol"},{key:"unenrolconfirm",component:"enrol",param:{user:i.data("fullname"),course:i.data("coursename"),enrolinstancename:i.data("enrolinstancename")}}],k=f.create({type:f.types.SAVE_CANCEL});b.when(c.get_strings(j),k).done(function(c,e){var f=c[0],i=c[1];e.setTitle(f),e.setBody(i),e.setSaveButtonText(f),e.getRoot().on(g.save,function(){var c={ueid:b(h).attr("rel")};d.preventDefault(),a.submitUnenrolFormAjax(e,c)}),e.getRoot().on(g.hidden,function(){e.destroy()}),e.show()}).fail(e.exception)})},k.prototype.bindStatusDetails=function(){b(j.SHOW_DETAILS).click(function(d){d.preventDefault();var h=b(this),i=h.parent(),k={fullname:i.data("fullname"),coursename:i.data("coursename"),enrolinstancename:i.data("enrolinstancename"),status:i.data("status"),statusclass:i.find("span").attr("class"),timestart:i.data("timestart"),timeend:i.data("timeend"),timeenrolled:i.data("timeenrolled")},l=[{key:"enroldetails",component:"enrol"}],m=h.next(j.EDIT_ENROLMENT);m.length&&(k.editenrollink=b("