diff --git a/enrol/cohort/lib.php b/enrol/cohort/lib.php
index 179671e122c..7c1eef26803 100644
--- a/enrol/cohort/lib.php
+++ b/enrol/cohort/lib.php
@@ -236,7 +236,9 @@ class enrol_cohort_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/cohort:unenrol', $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
return $actions;
}
diff --git a/enrol/database/lib.php b/enrol/database/lib.php
index b21578e5fc2..890942a47bf 100644
--- a/enrol/database/lib.php
+++ b/enrol/database/lib.php
@@ -97,7 +97,9 @@ class enrol_database_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/database:unenrol', $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
return $actions;
}
diff --git a/enrol/editenrolment.php b/enrol/editenrolment.php
index 8b6f54efe11..54f18efc46e 100644
--- a/enrol/editenrolment.php
+++ b/enrol/editenrolment.php
@@ -41,7 +41,7 @@ $instance = $DB->get_record('enrol', array('id'=>$ue->enrolid), '*', MUST_EXIST)
$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST);
// The URL of the enrolled users page for the course.
-$usersurl = new moodle_url('/enrol/users.php', array('id' => $course->id));
+$usersurl = new moodle_url('/user/index.php', array('id' => $course->id));
// Do not allow any changes if plugin disabled, not available or not suitable.
if (!$plugin = enrol_get_plugin($instance->enrol)) {
diff --git a/enrol/editenrolment_form.php b/enrol/editenrolment_form.php
index 8bdc46611de..307346c4125 100644
--- a/enrol/editenrolment_form.php
+++ b/enrol/editenrolment_form.php
@@ -28,15 +28,10 @@ require_once("$CFG->libdir/formslib.php");
class enrol_user_enrolment_form extends moodleform {
function definition() {
- global $CFG, $DB;
-
$mform = $this->_form;
- $user = $this->_customdata['user'];
- $course = $this->_customdata['course'];
- $ue = $this->_customdata['ue'];
-
- $mform->addElement('header','general', '');
+ $ue = $this->_customdata['ue'];
+ $modal = !empty($this->_customdata['modal']);
$options = array(ENROL_USER_ACTIVE => get_string('participationactive', 'enrol'),
ENROL_USER_SUSPENDED => get_string('participationsuspended', 'enrol'));
@@ -56,7 +51,10 @@ class enrol_user_enrolment_form extends moodleform {
$mform->addElement('hidden', 'ifilter');
$mform->setType('ifilter', PARAM_ALPHA);
- $this->add_action_buttons();
+ // Show action buttons if this is not being rendered as a fragment.
+ if (!$modal) {
+ $this->add_action_buttons();
+ }
$this->set_data(array(
'ue' => $ue->id,
@@ -71,8 +69,7 @@ class enrol_user_enrolment_form extends moodleform {
if (!empty($data['timestart']) and !empty($data['timeend'])) {
if ($data['timestart'] >= $data['timeend']) {
- $errors['timestart'] = get_string('error');
- $errors['timeend'] = get_string('error');
+ $errors['timeend'] = get_string('enroltimeendinvalid', 'enrol');
}
}
diff --git a/enrol/externallib.php b/enrol/externallib.php
index f8244225f84..370141a44ef 100644
--- a/enrol/externallib.php
+++ b/enrol/externallib.php
@@ -805,6 +805,107 @@ class core_enrol_external extends external_api {
)
);
}
+
+ /**
+ * Returns description of edit_user_enrolment() parameters
+ *
+ * @return external_function_parameters
+ */
+ public static function edit_user_enrolment_parameters() {
+ return new external_function_parameters(
+ array(
+ 'courseid' => new external_value(PARAM_INT, 'User enrolment ID'),
+ 'ueid' => new external_value(PARAM_INT, 'User enrolment ID'),
+ 'status' => new external_value(PARAM_INT, 'Enrolment status'),
+ 'timestart' => new external_value(PARAM_INT, 'Enrolment start timestamp', VALUE_DEFAULT, 0),
+ 'timeend' => new external_value(PARAM_INT, 'Enrolment end timestamp', VALUE_DEFAULT, 0),
+ )
+ );
+ }
+
+ /**
+ * External function that updates a given user enrolment.
+ *
+ * @param int $courseid The course ID.
+ * @param int $ueid The user enrolment ID.
+ * @param int $status The enrolment status.
+ * @param int $timestart Enrolment start timestamp.
+ * @param int $timeend Enrolment end timestamp.
+ * @return array An array consisting of the processing result, errors and form output, if available.
+ */
+ public static function edit_user_enrolment($courseid, $ueid, $status, $timestart = 0, $timeend = 0) {
+ global $CFG, $DB, $PAGE;
+
+ $params = self::validate_parameters(self::edit_user_enrolment_parameters(), [
+ 'courseid' => $courseid,
+ 'ueid' => $ueid,
+ 'status' => $status,
+ 'timestart' => $timestart,
+ 'timeend' => $timeend,
+ ]);
+
+ $course = get_course($courseid);
+ $context = context_course::instance($course->id);
+ self::validate_context($context);
+
+ $userenrolment = $DB->get_record('user_enrolments', ['id' => $params['ueid']], '*', MUST_EXIST);
+ $userenroldata = [
+ 'status' => $params['status'],
+ 'timestart' => $params['timestart'],
+ 'timeend' => $params['timeend'],
+ ];
+
+ $result = false;
+ $errors = [];
+
+ // Validate data against the edit user enrolment form.
+ require_once("$CFG->dirroot/enrol/editenrolment_form.php");
+ $customformdata = [
+ 'ue' => $userenrolment,
+ 'modal' => true,
+ ];
+ $mform = new \enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $userenroldata);
+ $mform->set_data($userenroldata);
+ $validationerrors = $mform->validation($userenroldata, null);
+ if (empty($validationerrors)) {
+ require_once($CFG->dirroot . '/enrol/locallib.php');
+ $manager = new course_enrolment_manager($PAGE, $course);
+ $result = $manager->edit_enrolment($userenrolment, (object)$userenroldata);
+ } else {
+ foreach ($validationerrors as $key => $errormessage) {
+ $errors[] = (object)[
+ 'key' => $key,
+ 'message' => $errormessage
+ ];
+ }
+ }
+
+ return [
+ 'result' => $result,
+ 'errors' => $errors,
+ ];
+ }
+
+ /**
+ * Returns description of edit_user_enrolment() result value
+ *
+ * @return external_description
+ */
+ public static function edit_user_enrolment_returns() {
+ return new external_single_structure(
+ array(
+ 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
+ 'errors' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'key' => new external_value(PARAM_TEXT, 'The data that failed the validation'),
+ 'message' => new external_value(PARAM_TEXT, 'The error message'),
+ )
+ ), 'List of validation errors'
+ ),
+ )
+ );
+ }
}
/**
diff --git a/enrol/flatfile/lib.php b/enrol/flatfile/lib.php
index 4bff2a9939a..498584819bb 100644
--- a/enrol/flatfile/lib.php
+++ b/enrol/flatfile/lib.php
@@ -132,11 +132,14 @@ class enrol_flatfile_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/flatfile:unenrol", $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
if ($this->allow_manage($instance) && has_capability("enrol/flatfile:manage", $context)) {
$url = new moodle_url('/enrol/editenrolment.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
+ $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, $actionparams);
}
return $actions;
}
diff --git a/enrol/lti/lib.php b/enrol/lti/lib.php
index 1377b197815..0edfbfbdcac 100644
--- a/enrol/lti/lib.php
+++ b/enrol/lti/lib.php
@@ -392,13 +392,14 @@ class enrol_lti_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/lti:unenrol", $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
$actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
- array('class' => 'unenrollink', 'rel' => $ue->id));
+ $actionparams);
}
if ($this->allow_manage($instance) && has_capability("enrol/lti:manage", $context)) {
$url = new moodle_url('/enrol/editenrolment.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url,
- array('class' => 'editenrollink', 'rel' => $ue->id));
+ $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
+ $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, $actionparams);
}
return $actions;
}
diff --git a/enrol/manual/lib.php b/enrol/manual/lib.php
index 1eef9b01cbb..c71c2467050 100644
--- a/enrol/manual/lib.php
+++ b/enrol/manual/lib.php
@@ -376,11 +376,14 @@ class enrol_manual_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/manual:unenrol", $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
if ($this->allow_manage($instance) && has_capability("enrol/manual:manage", $context)) {
$url = new moodle_url('/enrol/editenrolment.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
+ $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, $actionparams);
}
return $actions;
}
diff --git a/enrol/meta/lib.php b/enrol/meta/lib.php
index 1415f57010d..0b6bfd0171e 100644
--- a/enrol/meta/lib.php
+++ b/enrol/meta/lib.php
@@ -110,7 +110,9 @@ class enrol_meta_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/meta:unenrol', $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
return $actions;
}
diff --git a/enrol/meta/tests/behat/enrol_meta.feature b/enrol/meta/tests/behat/enrol_meta.feature
index f8ba1731044..447822973a3 100644
--- a/enrol/meta/tests/behat/enrol_meta.feature
+++ b/enrol/meta/tests/behat/enrol_meta.feature
@@ -16,18 +16,21 @@ Feature: Enrolments are synchronised with meta courses
| Course 1 | C1C1 |
| Course 2 | C2C2 |
| Course 3 | C3C3 |
+ | Course 4 | C4C4 |
And the following "groups" exist:
| name | course | idnumber |
| Groupcourse 1 | C3C3 | G1 |
| Groupcourse 2 | C3C3 | G2 |
And the following "course enrolments" exist:
- | user | course | role |
- | student1 | C1C1 | student |
- | student2 | C1C1 | student |
- | student3 | C1C1 | student |
- | student4 | C1C1 | student |
- | student1 | C2C2 | student |
- | student2 | C2C2 | student |
+ | user | course | role | status |
+ | student1 | C1C1 | student | 0 |
+ | student2 | C1C1 | student | 0 |
+ | student3 | C1C1 | student | 0 |
+ | student4 | C1C1 | student | 0 |
+ | student1 | C2C2 | student | 0 |
+ | student2 | C2C2 | student | 0 |
+ | student1 | C4C4 | student | 0 |
+ | student2 | C4C4 | student | 1 |
And I log in as "admin"
And I navigate to "Manage enrol plugins" node in "Site administration > Plugins > Enrolments"
And I click on "Enable" "link" in the "Course meta link" "table_row"
@@ -105,3 +108,13 @@ Feature: Enrolments are synchronised with meta courses
And I should see "Groupcourse 1" in the "Student 4" "table_row"
And I should see "Course 2" in the "Student 1" "table_row"
And I should not see "Course 2" in the "Student 3" "table_row"
+
+ Scenario: Unenrol a user from the course participants page that was enrolled via course meta link.
+ Given I am on "Course 3" course homepage
+ And I add "Course meta link" enrolment method with:
+ | Link course | C4C4 |
+ And I navigate to course participants
+ # Suspended users can be unenrolled.
+ When I click on "//a[@data-action='unenrol']" "xpath_element" in the "student2" "table_row"
+ And I click on "Yes" "button"
+ Then I should not see "Student 2" in the "participants" "table"
diff --git a/enrol/paypal/lib.php b/enrol/paypal/lib.php
index 87ecfe56ee8..7ec6722175b 100644
--- a/enrol/paypal/lib.php
+++ b/enrol/paypal/lib.php
@@ -291,11 +291,14 @@ class enrol_paypal_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol($instance) && has_capability("enrol/paypal:unenrol", $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
if ($this->allow_manage($instance) && has_capability("enrol/paypal:manage", $context)) {
$url = new moodle_url('/enrol/editenrolment.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
+ $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, $actionparams);
}
return $actions;
}
diff --git a/enrol/self/lib.php b/enrol/self/lib.php
index 90be25aac53..3519f76fe11 100644
--- a/enrol/self/lib.php
+++ b/enrol/self/lib.php
@@ -536,11 +536,14 @@ class enrol_self_plugin extends enrol_plugin {
$params['ue'] = $ue->id;
if ($this->allow_unenrol($instance) && has_capability("enrol/self:unenrol", $context)) {
$url = new moodle_url('/enrol/unenroluser.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
+ $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url,
+ $actionparams);
}
if ($this->allow_manage($instance) && has_capability("enrol/self:manage", $context)) {
$url = new moodle_url('/enrol/editenrolment.php', $params);
- $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id));
+ $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
+ $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, $actionparams);
}
return $actions;
}
diff --git a/enrol/self/tests/behat/self_enrolment.feature b/enrol/self/tests/behat/self_enrolment.feature
index b38fb108ae4..332e3af7fdf 100644
--- a/enrol/self/tests/behat/self_enrolment.feature
+++ b/enrol/self/tests/behat/self_enrolment.feature
@@ -87,3 +87,41 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
Then I should see "Topic 1"
And I should not see "Enrolment options"
And I should not see "Enrol me in this course"
+
+ @javascript
+ Scenario: Edit a self-enrolled user's enrolment from the course participants page
+ Given I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ When I add "Self enrolment" enrolment method with:
+ | Custom instance name | Test student enrolment |
+ And I log out
+ And I log in as "student1"
+ And I am on "Course 1" course homepage
+ And I press "Enrol me"
+ And I log out
+ And I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ And I navigate to course participants
+ When I click on "//a[@data-action='editenrolment']" "xpath_element" in the "student1" "table_row"
+ And I should see "Edit Student 1's enrolment"
+ And I set the field "Status" to "Suspended"
+ And I click on "Save changes" "button"
+ Then I should see "Suspended" in the "student1" "table_row"
+
+ @javascript
+ Scenario: Unenrol a self-enrolled student from the course participants page
+ Given I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ When I add "Self enrolment" enrolment method with:
+ | Custom instance name | Test student enrolment |
+ And I log out
+ And I log in as "student1"
+ And I am on "Course 1" course homepage
+ And I press "Enrol me"
+ And I log out
+ And I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ And I navigate to course participants
+ When I click on "//a[@data-action='unenrol']" "xpath_element" in the "student1" "table_row"
+ And I click on "Yes" "button"
+ Then I should not see "Student 1" in the "participants" "table"
diff --git a/enrol/tests/externallib_test.php b/enrol/tests/externallib_test.php
index b3e061dda80..8b787a145ec 100644
--- a/enrol/tests/externallib_test.php
+++ b/enrol/tests/externallib_test.php
@@ -682,4 +682,86 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals($data->student1->id, $expecteduser['id']);
}
+ /**
+ * Test for core_enrol_external::edit_user_enrolment().
+ */
+ public function test_edit_user_enrolment() {
+ global $DB;
+
+ $this->resetAfterTest(true);
+ $datagen = $this->getDataGenerator();
+
+ /** @var enrol_manual_plugin $manualplugin */
+ $manualplugin = enrol_get_plugin('manual');
+ $this->assertNotNull($manualplugin);
+
+ $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.
+ $this->setUser($teacher);
+
+ $now = new DateTime();
+ $nowtime = $now->getTimestamp();
+
+ // Invalid data.
+ $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nowtime);
+ $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data);
+ $this->assertFalse($data['result']);
+ $this->assertNotEmpty($data['errors']);
+
+ // Valid data.
+ $nextmonth = clone($now);
+ $nextmonth->add(new DateInterval('P1M'));
+ $nextmonthtime = $nextmonth->getTimestamp();
+ $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nextmonthtime);
+ $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data);
+ $this->assertTrue($data['result']);
+ $this->assertEmpty($data['errors']);
+
+ // Check updated user enrolment.
+ $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
+ $this->assertEquals(ENROL_USER_ACTIVE, $ue->status);
+ $this->assertEquals($nowtime, $ue->timestart);
+ $this->assertEquals($nextmonthtime, $ue->timeend);
+
+ // Suspend user.
+ $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_SUSPENDED);
+ $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data);
+ $this->assertTrue($data['result']);
+ $this->assertEmpty($data['errors']);
+
+ // Check updated user enrolment.
+ $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
+ $this->assertEquals(ENROL_USER_SUSPENDED, $ue->status);
+ }
}
diff --git a/enrol/unenroluser.php b/enrol/unenroluser.php
index 99033919001..fe1fc18d190 100644
--- a/enrol/unenroluser.php
+++ b/enrol/unenroluser.php
@@ -58,8 +58,7 @@ if (!$plugin->allow_unenrol_user($instance, $ue) or !has_capability("enrol/$inst
$manager = new course_enrolment_manager($PAGE, $course, $filter);
$table = new course_enrolment_users_table($manager, $PAGE);
-$returnurl = new moodle_url('/enrol/users.php', array('id' => $course->id)+$manager->get_url_params()+$table->get_url_params());
-$usersurl = new moodle_url('/enrol/users.php', array('id' => $course->id));
+$usersurl = new moodle_url('/user/index.php', array('id' => $course->id));
$PAGE->set_pagelayout('admin');
navigation_node::override_active_url($usersurl);
@@ -67,7 +66,7 @@ navigation_node::override_active_url($usersurl);
// If the unenrolment has been confirmed and the sesskey is valid unenrol the user.
if ($confirm && confirm_sesskey()) {
$plugin->unenrol_user($instance, $ue->userid);
- redirect($returnurl);
+ redirect($usersurl);
}
$yesurl = new moodle_url($PAGE->url, array('confirm'=>1, 'sesskey'=>sesskey()));
@@ -82,5 +81,5 @@ $PAGE->navbar->add($fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading($fullname);
-echo $OUTPUT->confirm($message, $yesurl, $returnurl);
+echo $OUTPUT->confirm($message, $yesurl, $usersurl);
echo $OUTPUT->footer();
diff --git a/lang/en/enrol.php b/lang/en/enrol.php
index f9c026d5c45..ae18f7ce4fc 100644
--- a/lang/en/enrol.php
+++ b/lang/en/enrol.php
@@ -43,11 +43,13 @@ $string['deleteinstancenousersconfirm'] = 'You are about to delete the enrolment
$string['disableinstanceconfirmself'] = 'Are you really sure you want to disable instance "{$a->name}" that gives you access to this course? It is possible that you will not be able to access this course if you continue.';
$string['durationdays'] = '{$a} days';
$string['editenrolment'] = 'Edit enrolment';
+$string['edituserenrolment'] = 'Edit {$a}\'s enrolment';
$string['enrol'] = 'Enrol';
$string['enrolcandidates'] = 'Not enrolled users';
$string['enrolcandidatesmatching'] = 'Matching not enrolled users';
$string['enrolcohort'] = 'Enrol cohort';
$string['enrolcohortusers'] = 'Enrol users';
+$string['enroldetails'] = 'Enrolment details';
$string['eventenrolinstancecreated'] = 'Enrolment instance created';
$string['eventenrolinstancedeleted'] = 'Enrolment instance deleted';
$string['eventenrolinstanceupdated'] = 'Enrolment instance updated';
@@ -58,6 +60,7 @@ $string['enrolme'] = 'Enrol me in this course';
$string['enrolmentinstances'] = 'Enrolment methods';
$string['enrolmentnew'] = 'New enrolment in {$a}';
$string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"';
+$string['enrolmentmethod'] = 'Enrolment method';
$string['enrolments'] = 'Enrolments';
$string['enrolmentoptions'] = 'Enrolment options';
$string['enrolnotpermitted'] = 'You do not have permission or are not allowed to enrol someone in this course';
@@ -67,6 +70,7 @@ $string['enrolusers'] = 'Enrol users';
$string['enrolxusers'] = 'Enrol {$a} users';
$string['enroltimecreated'] = 'Enrolment created';
$string['enroltimeend'] = 'Enrolment ends';
+$string['enroltimeendinvalid'] = 'Enrolment end date must be after the enrolment start date';
$string['enroltimestart'] = 'Enrolment starts';
$string['errajaxfailedenrol'] = 'Failed to enrol user';
$string['errajaxsearch'] = 'Error when searching users';
@@ -104,6 +108,7 @@ $string['notenrollable'] = 'You can not enrol yourself in this course.';
$string['notenrolledusers'] = 'Other users';
$string['otheruserdesc'] = 'The following users are not enrolled in this course but do have roles, inherited or assigned within it.';
$string['participationactive'] = 'Active';
+$string['participationnotcurrent'] = 'Not current';
$string['participationstatus'] = 'Status';
$string['participationsuspended'] = 'Suspended';
$string['periodend'] = 'until {$a}';
diff --git a/lib/db/services.php b/lib/db/services.php
index d483578e06b..14385ae6628 100644
--- a/lib/db/services.php
+++ b/lib/db/services.php
@@ -482,6 +482,14 @@ $functions = array(
'capabilities' => 'moodle/course:viewparticipants',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
+ 'core_enrol_edit_user_enrolment' => array(
+ 'classname' => 'core_enrol_external',
+ 'methodname' => 'edit_user_enrolment',
+ 'classpath' => 'enrol/externallib.php',
+ 'description' => 'External function that updates a given user enrolment',
+ 'type' => 'write',
+ 'ajax' => true,
+ ),
'core_fetch_notifications' => array(
'classname' => 'core_external',
'methodname' => 'fetch_notifications',
diff --git a/lib/enrollib.php b/lib/enrollib.php
index 7157bc5ebbf..93f67dc2890 100644
--- a/lib/enrollib.php
+++ b/lib/enrollib.php
@@ -87,6 +87,12 @@ define('ENROL_SEND_EMAIL_FROM_KEY_HOLDER', 2);
*/
define('ENROL_SEND_EMAIL_FROM_NOREPLY', 3);
+/** Edit enrolment action. */
+define('ENROL_ACTION_EDIT', 'editenrolment');
+
+/** Unenrol action. */
+define('ENROL_ACTION_UNENROL', 'unenrol');
+
/**
* Returns instances of enrol plugins
* @param bool $enabled return enabled only
@@ -1414,6 +1420,44 @@ function enrol_send_welcome_email_options() {
];
}
+/**
+ * Serve the user enrolment form as a fragment.
+ *
+ * @param array $args List of named arguments for the fragment loader.
+ * @return string
+ */
+function enrol_output_fragment_user_enrolment_form($args) {
+ global $CFG, $DB;
+
+ $args = (object) $args;
+ $context = $args->context;
+ require_capability('moodle/course:enrolreview', $context);
+
+ $ueid = $args->ueid;
+ $userenrolment = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
+ $customdata = [
+ 'ue' => $userenrolment,
+ 'modal' => true,
+ ];
+
+ // Set the data if applicable.
+ $data = [];
+ if (isset($args->formdata)) {
+ $serialiseddata = json_decode($args->formdata);
+ parse_str($serialiseddata, $data);
+ }
+
+ require_once("$CFG->dirroot/enrol/editenrolment_form.php");
+ $mform = new \enrol_user_enrolment_form(null, $customdata, 'post', '', null, true, $data);
+
+ if (!empty($data)) {
+ $mform->set_data($data);
+ $mform->is_validated();
+ }
+
+ return $mform->render();
+}
+
/**
* Returns the course where a user enrolment belong to.
*
diff --git a/lib/upgrade.txt b/lib/upgrade.txt
index ef21b435245..ea0eace1434 100644
--- a/lib/upgrade.txt
+++ b/lib/upgrade.txt
@@ -25,6 +25,13 @@ information provided here is intended especially for developers.
every form. The method should accept a single parameter with the submitted value. It should return a string with the
eventual validation error, or an empty value if the validation passes.
* New user_picture attribute $includefullname to determine whether to include the user's full name with the user's picture.
+* Enrol plugins which provide enrolment actions can now declare the following "data-action" attributes in their implementation of
+ enrol_plugin::get_user_enrolment_actions() whenever applicable:
+ * "editenrolment" - For editing a user'e enrolment details. Defined by constant ENROL_ACTION_EDIT.
+ * "unenrol" - For unenrolling a student. Defined by constant ENROL_ACTION_UNENROL.
+ These attributes enable enrol actions to be rendered via modals. If not added, clicking on the enrolment action buttons will still
+ redirect the user to the appropriate enrolment action page. Though optional, it is recommended to add these attributes for a
+ better user experience when performing enrol actions.
=== 3.3.1 ===
diff --git a/user/amd/build/status_field.min.js b/user/amd/build/status_field.min.js
new file mode 100644
index 00000000000..ea0b3656672
--- /dev/null
+++ b/user/amd/build/status_field.min.js
@@ -0,0 +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(){b(j.UNENROL).click(function(a){a.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")}}];b.when(c.get_strings(j)).then(function(a){var b=a[0],c=a[1];return f.create({body:c,large:!0,title:b,type:f.types.CONFIRM})}).done(function(a){a.getRoot().on(g.yes,function(){var a={confirm:1,sesskey:d.sesskey,ue:b(h).attr("rel")};window.location.href=d.wwwroot+"/enrol/unenroluser.php?"+b.param(a)}),a.getRoot().on(g.hidden,function(){a.destroy()}),a.show()}).fail(e.exception)})},k.prototype.bindStatusDetails=function(){b(j.SHOW_DETAILS).click(function(d){d.preventDefault();var h=b(this),i=h.parent(),j={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")},k=c.get_string("enroldetails","enrol"),l=f.create({large:!0,type:f.types.CANCEL});b.when(k,l).done(function(b,c){var d=a.render("core_user/status_details",j);c.setTitle(b),c.setBody(d),c.show(),c.getRoot().on(g.hidden,function(){c.destroy()})}).fail(e.exception)})},k.prototype.submitEditFormAjax=function(a){var c=this,d=a.getRoot().find("form"),f=b(d).find('[name="ue"]').val(),g=b(d).find('[name="status"]').val(),h={courseid:this.courseid,ueid:f,status:g},j=b(d).find('[name="timestart[enabled]"]');if(j.is(":checked")){var k=b(d).find('[name="timestart[year]"]').val(),l=b(d).find('[name="timestart[month]"]').val()-1,m=b(d).find('[name="timestart[day]"]').val(),n=b(d).find('[name="timestart[hour]"]').val(),o=b(d).find('[name="timestart[minute]"]').val(),p=new Date(k,l,m,n,o);h.timestart=p.getTime()/1e3}var q=b(d).find('[name="timeend[enabled]"]');if(q.is(":checked")){var r=b(d).find('[name="timeend[year]"]').val(),s=b(d).find('[name="timeend[month]"]').val()-1,t=b(d).find('[name="timeend[day]"]').val(),u=b(d).find('[name="timeend[hour]"]').val(),v=b(d).find('[name="timeend[minute]"]').val(),w=new Date(r,s,t,u,v);h.timeend=w.getTime()/1e3}var x={methodname:"core_enrol_edit_user_enrolment",args:h};i.call([x])[0].done(function(b){if(b.result)a.hide(),"undefined"!=typeof window.M.core_formchangechecker&&window.M.core_formchangechecker.reset_form_dirty_state(),window.location.reload();else{var e=JSON.stringify(d.serialize());a.setBody(c.getBody(f,e))}}).fail(e.exception)},k.prototype.getBody=function(a,b){var c={ueid:a};return"undefined"!=typeof b&&(c.formdata=b),h.loadFragment("enrol","user_enrolment_form",this.contextid,c).fail(e.exception)},{init:function(a){new k(a)}}});
\ No newline at end of file
diff --git a/user/amd/src/status_field.js b/user/amd/src/status_field.js
new file mode 100644
index 00000000000..e57b7e915b5
--- /dev/null
+++ b/user/amd/src/status_field.js
@@ -0,0 +1,323 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see
| + {{#str}}fullname{{/str}} + | ++ {{fullname}} + | +
|---|---|
| + {{#str}}course{{/str}} + | ++ {{coursename}} + | +
| + {{#str}}enrolmentmethod, enrol{{/str}} + | ++ {{enrolinstancename}} + | +
| + {{#str}}participationstatus, enrol{{/str}} + | ++ + {{status}} + + | +
| + {{#str}}enroltimestart, enrol{{/str}} + | ++ {{timestart}} + | +
| + {{#str}}enroltimeend, enrol{{/str}} + | ++ {{timeend}} + | +