diff --git a/.upgradenotes/MDL-84142-2025021805284040.yml b/.upgradenotes/MDL-84142-2025021805284040.yml
new file mode 100644
index 00000000000..b994c8b8c05
--- /dev/null
+++ b/.upgradenotes/MDL-84142-2025021805284040.yml
@@ -0,0 +1,7 @@
+issueNumber: MDL-84142
+notes:
+ enrol_guest:
+ - message: >-
+ Class enrol_guest_enrol_form is deprecated, use
+ enrol_guest\form\enrol_form instead
+ type: deprecated
diff --git a/enrol/guest/amd/build/enrol_page.min.js b/enrol/guest/amd/build/enrol_page.min.js
new file mode 100644
index 00000000000..30c2454a44b
--- /dev/null
+++ b/enrol/guest/amd/build/enrol_page.min.js
@@ -0,0 +1,10 @@
+define("enrol_guest/enrol_page",["exports","core_form/modalform","core/str","core/prefetch","core/url"],(function(_exports,_modalform,_str,_prefetch,_url){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
+/**
+ * Functions for the enrol_guest plugin
+ *
+ * @module enrol_guest/enrol_page
+ * @copyright Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.initEnrol=function(instanceId){(0,_prefetch.prefetchStrings)("moodle",["loginguest"]);const button=document.querySelector('button[type="submit"][data-instance="'+instanceId+'"]');button&&button.addEventListener("click",(e=>{e.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:button.dataset.title,large:!1},formClass:button.dataset.form,args:{id:button.dataset.id,instance:instanceId},saveButtonText:(0,_str.getString)("loginguest","moodle"),returnFocus:button});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(event=>{window.location.href=event.detail?event.detail:_url.default.relativeUrl("/course/view.php",{id:button.dataset.id})})),modalForm.show()}))},_modalform=_interopRequireDefault(_modalform),_url=_interopRequireDefault(_url)}));
+
+//# sourceMappingURL=enrol_page.min.js.map
\ No newline at end of file
diff --git a/enrol/guest/amd/build/enrol_page.min.js.map b/enrol/guest/amd/build/enrol_page.min.js.map
new file mode 100644
index 00000000000..04289bba68f
--- /dev/null
+++ b/enrol/guest/amd/build/enrol_page.min.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"enrol_page.min.js","sources":["../src/enrol_page.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Functions for the enrol_guest plugin\n *\n * @module enrol_guest/enrol_page\n * @copyright Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalForm from 'core_form/modalform';\nimport {getString} from 'core/str';\nimport {prefetchStrings} from 'core/prefetch';\nimport Url from 'core/url';\n\n/**\n * Initialise widget on the course enrolment page - clicking on the button should submit the form\n *\n * @param {Number} instanceId\n */\nexport function initEnrol(instanceId) {\n prefetchStrings('moodle', [\n 'loginguest',\n ]);\n\n const button = document.querySelector('button[type=\"submit\"][data-instance=\"' + instanceId + '\"]');\n if (button) {\n button.addEventListener('click', (e) => {\n e.preventDefault();\n const modalForm = new ModalForm({\n modalConfig: {\n title: button.dataset.title,\n large: false, // This is a very small form that does not need a large popup.\n },\n formClass: button.dataset.form,\n args: {id: button.dataset.id, instance: instanceId},\n saveButtonText: getString('loginguest', 'moodle'),\n returnFocus: button,\n });\n\n // Redirect to the course page when the form is submitted.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {\n window.location.href = event.detail ? event.detail :\n Url.relativeUrl('/course/view.php', {id: button.dataset.id});\n });\n\n modalForm.show();\n });\n }\n}\n"],"names":["instanceId","button","document","querySelector","addEventListener","e","preventDefault","modalForm","ModalForm","modalConfig","title","dataset","large","formClass","form","args","id","instance","saveButtonText","returnFocus","events","FORM_SUBMITTED","event","window","location","href","detail","Url","relativeUrl","show"],"mappings":";;;;;;;yFAiC0BA,0CACN,SAAU,CACtB,qBAGEC,OAASC,SAASC,cAAc,wCAA0CH,WAAa,MACzFC,QACAA,OAAOG,iBAAiB,SAAUC,IAC9BA,EAAEC,uBACIC,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,MAAOT,OAAOU,QAAQD,MACtBE,OAAO,GAEXC,UAAWZ,OAAOU,QAAQG,KAC1BC,KAAM,CAACC,GAAIf,OAAOU,QAAQK,GAAIC,SAAUjB,YACxCkB,gBAAgB,kBAAU,aAAc,UACxCC,YAAalB,SAIjBM,UAAUH,iBAAiBG,UAAUa,OAAOC,gBAAgBC,QACxDC,OAAOC,SAASC,KAAOH,MAAMI,OAASJ,MAAMI,OACxCC,aAAIC,YAAY,mBAAoB,CAACZ,GAAIf,OAAOU,QAAQK,QAGhET,UAAUsB"}
\ No newline at end of file
diff --git a/enrol/guest/amd/src/enrol_page.js b/enrol/guest/amd/src/enrol_page.js
new file mode 100644
index 00000000000..b792d5089be
--- /dev/null
+++ b/enrol/guest/amd/src/enrol_page.js
@@ -0,0 +1,63 @@
+// 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 .
+
+/**
+ * Functions for the enrol_guest plugin
+ *
+ * @module enrol_guest/enrol_page
+ * @copyright Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+import ModalForm from 'core_form/modalform';
+import {getString} from 'core/str';
+import {prefetchStrings} from 'core/prefetch';
+import Url from 'core/url';
+
+/**
+ * Initialise widget on the course enrolment page - clicking on the button should submit the form
+ *
+ * @param {Number} instanceId
+ */
+export function initEnrol(instanceId) {
+ prefetchStrings('moodle', [
+ 'loginguest',
+ ]);
+
+ const button = document.querySelector('button[type="submit"][data-instance="' + instanceId + '"]');
+ if (button) {
+ button.addEventListener('click', (e) => {
+ e.preventDefault();
+ const modalForm = new ModalForm({
+ modalConfig: {
+ title: button.dataset.title,
+ large: false, // This is a very small form that does not need a large popup.
+ },
+ formClass: button.dataset.form,
+ args: {id: button.dataset.id, instance: instanceId},
+ saveButtonText: getString('loginguest', 'moodle'),
+ returnFocus: button,
+ });
+
+ // Redirect to the course page when the form is submitted.
+ modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {
+ window.location.href = event.detail ? event.detail :
+ Url.relativeUrl('/course/view.php', {id: button.dataset.id});
+ });
+
+ modalForm.show();
+ });
+ }
+}
diff --git a/enrol/guest/classes/form/enrol_form.php b/enrol/guest/classes/form/enrol_form.php
new file mode 100644
index 00000000000..c3d43976c22
--- /dev/null
+++ b/enrol/guest/classes/form/enrol_form.php
@@ -0,0 +1,150 @@
+.
+
+declare(strict_types=1);
+
+namespace enrol_guest\form;
+
+use core\context\course as context_course;
+use core_form\dynamic_form;
+use core_text;
+use moodle_url;
+
+/**
+ * Form for entering password for guest enrolment
+ *
+ * @package enrol_guest
+ * @copyright Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class enrol_form extends dynamic_form {
+ /** @var \stdClass */
+ protected $instance;
+
+ /**
+ * Returns the instance of the enrolment method
+ *
+ * @throws \moodle_exception
+ * @return \stdClass
+ */
+ protected function get_instance(): \stdClass {
+ global $DB, $CFG;
+ require_once($CFG->dirroot . '/lib/enrollib.php');
+ if ($this->instance === null) {
+ $courseid = $this->optional_param('id', 0, PARAM_INT);
+ $instanceid = $this->optional_param('instance', 0, PARAM_INT);
+ // We need enrol_get_instances() to validate that the enrolment method is enabled.
+ $instances = enrol_get_instances($courseid, true);
+ if (empty($instances[$instanceid]) || $instances[$instanceid]->enrol !== 'guest') {
+ throw new \moodle_exception('invalidenrolinstance', 'enrol');
+ }
+ $this->instance = $instances[$instanceid] ?? null;
+ }
+ return $this->instance;
+ }
+
+ #[\Override]
+ public function definition() {
+ $mform = $this->_form;
+
+ $mform->addElement('password', 'guestpassword', get_string('password', 'enrol_guest'));
+
+ $mform->addElement('hidden', 'id');
+ $mform->setType('id', PARAM_INT);
+
+ $mform->addElement('hidden', 'instance');
+ $mform->setType('instance', PARAM_INT);
+ }
+
+ #[\Override]
+ public function validation($data, $files) {
+ global $DB, $CFG;
+
+ $errors = parent::validation($data, $files);
+ $instance = $this->get_instance();
+
+ if ($instance->password !== '') {
+ if ($data['guestpassword'] !== $instance->password) {
+ $plugin = enrol_get_plugin('guest');
+ if ($plugin->get_config('showhint')) {
+ $hint = core_text::substr($instance->password, 0, 1);
+ $errors['guestpassword'] = get_string('passwordinvalidhint', 'enrol_guest', $hint);
+ } else {
+ $errors['guestpassword'] = get_string('passwordinvalid', 'enrol_guest');
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+ #[\Override]
+ protected function check_access_for_dynamic_submission(): void {
+ global $USER, $CFG;
+ $courseid = $this->get_instance()->courseid;
+ $course = get_course($courseid);
+ $context = context_course::instance($this->get_instance()->courseid);
+ if (!\core_course_category::can_view_course_info($course) && !is_enrolled($context, $USER, '', true)) {
+ throw new \moodle_exception('coursehidden', '', $CFG->wwwroot . '/');
+ }
+ }
+
+ #[\Override]
+ protected function get_context_for_dynamic_submission(): \context {
+ // This form is used for users who are not yet enrolled in the course and do not have access to the course.
+ // For the purpose of permission checks they must be able to access the course category for this course.
+ return context_course::instance($this->get_instance()->courseid)->get_parent_context();
+ }
+
+ #[\Override]
+ protected function get_page_url_for_dynamic_submission(): moodle_url {
+ $instance = $this->get_instance();
+ return new moodle_url('/enrol/index.php', ['id' => $instance->courseid, 'instance' => $instance->id]);
+ }
+
+ /**
+ * Process the form submission, used if form was submitted via AJAX
+ *
+ * Enrols the user in the course and returns the URL to redirect to
+ *
+ * @return string
+ */
+ public function process_dynamic_submission() {
+ global $USER, $CFG, $SESSION;
+
+ /** @var \enrol_guest_plugin $enrol */
+ $enrol = enrol_get_plugin('guest');
+ $instance = $this->get_instance();
+
+ $enrol->mark_user_as_enrolled($instance, $this->get_data()->guestpassword);
+
+ // Go to the originally requested page.
+ if (!empty($SESSION->wantsurl)) {
+ $destination = $SESSION->wantsurl;
+ unset($SESSION->wantsurl);
+ } else {
+ require_once($CFG->dirroot . '/course/lib.php');
+ $destination = course_get_url($instance->courseid);
+ }
+ return $destination;
+ }
+
+ #[\Override]
+ public function set_data_for_dynamic_submission(): void {
+ $instance = $this->get_instance();
+ $this->set_data(['id' => $instance->courseid, 'instance' => $instance->id]);
+ }
+}
diff --git a/enrol/guest/lang/en/enrol_guest.php b/enrol/guest/lang/en/enrol_guest.php
index bed0a5a85f2..bdd3f930124 100644
--- a/enrol/guest/lang/en/enrol_guest.php
+++ b/enrol/guest/lang/en/enrol_guest.php
@@ -31,6 +31,7 @@ $string['password_help'] = 'A password allows guest access to the course to be r
$string['passwordinvalid'] = 'Incorrect access password, please try again';
$string['passwordinvalidhint'] = 'That access password was incorrect, please try again
(Here\'s a hint - it starts with \'{$a}\')';
+$string['passwordrequired'] = 'A password will be required';
$string['pluginname'] = 'Guest access';
$string['pluginname_desc'] = 'Guest access plugin is only granting temporary access to courses, it is not actually enrolling users.';
$string['requirepassword'] = 'Require guest access password';
diff --git a/enrol/guest/lib.php b/enrol/guest/lib.php
index 1af049f19d1..e32c8754dec 100644
--- a/enrol/guest/lib.php
+++ b/enrol/guest/lib.php
@@ -25,7 +25,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-defined('MOODLE_INTERNAL') || die();
+use core\output\single_button;
+use core_enrol\output\enrol_page;
/**
* Class enrol_guest_plugin
@@ -148,14 +149,28 @@ class enrol_guest_plugin extends enrol_plugin {
}
/**
- * Creates course enrol form, checks if form submitted
- * and enrols user if necessary. It can also redirect.
+ * Enrol a user using the guest enrolment method
*
* @param stdClass $instance
- * @return string html text, usually a form in a text box
+ * @param string $guestpassword
+ * @return void
*/
+ public function mark_user_as_enrolled(stdClass $instance, string $guestpassword): void {
+ global $USER, $CFG;
+
+ // Add guest role.
+ $context = \core\context\course::instance($instance->courseid);
+ $USER->enrol_guest_passwords[$instance->id] = $guestpassword;
+ if (isset($USER->enrol['tempguest'][$instance->courseid])) {
+ remove_temp_course_roles($context);
+ }
+ load_temp_course_role($context, $CFG->guestroleid);
+ $USER->enrol['tempguest'][$instance->courseid] = ENROL_MAX_TIMESTAMP;
+ }
+
+ #[\Override]
public function enrol_page_hook(stdClass $instance) {
- global $CFG, $OUTPUT, $SESSION, $USER;
+ global $CFG, $OUTPUT, $SESSION, $USER, $PAGE;
if ($instance->password === '') {
return null;
@@ -166,37 +181,27 @@ class enrol_guest_plugin extends enrol_plugin {
return null;
}
- require_once("$CFG->dirroot/enrol/guest/locallib.php");
- $form = new enrol_guest_enrol_form(NULL, $instance);
- $instanceid = optional_param('instance', 0, PARAM_INT);
-
- if ($instance->id == $instanceid) {
- if ($data = $form->get_data()) {
- // add guest role
- $context = context_course::instance($instance->courseid);
- $USER->enrol_guest_passwords[$instance->id] = $data->guestpassword; // this is a hack, ideally we should not add stuff to $USER...
- if (isset($USER->enrol['tempguest'][$instance->courseid])) {
- remove_temp_course_roles($context);
- }
- load_temp_course_role($context, $CFG->guestroleid);
- $USER->enrol['tempguest'][$instance->courseid] = ENROL_MAX_TIMESTAMP;
-
- // go to the originally requested page
- if (!empty($SESSION->wantsurl)) {
- $destination = $SESSION->wantsurl;
- unset($SESSION->wantsurl);
- } else {
- $destination = "$CFG->wwwroot/course/view.php?id=$instance->courseid";
- }
- redirect($destination);
- }
- }
-
- ob_start();
- $form->display();
- $output = ob_get_clean();
-
- return $OUTPUT->box($output, 'generalbox');
+ $title = $this->get_instance_name($instance);
+ $notification = new \core\output\notification(get_string('passwordrequired', 'enrol_guest'), 'info', false);
+ $notification->set_extra_classes(['mb-0']);
+ $button = new single_button(
+ $PAGE->url,
+ get_string('loginguest', 'moodle'),
+ 'get',
+ single_button::BUTTON_PRIMARY,
+ [
+ 'data-id' => $instance->courseid,
+ 'data-instance' => $instance->id,
+ 'data-form' => enrol_guest\form\enrol_form::class,
+ 'data-title' => $title,
+ ]);
+ $PAGE->requires->js_call_amd('enrol_guest/enrol_page', 'initEnrol', [$instance->id]);
+ $enrolpage = new enrol_page(
+ instance: $instance,
+ header: $title,
+ body: $OUTPUT->render($notification),
+ buttons: [$button]);
+ return $OUTPUT->render($enrolpage);
}
/**
diff --git a/enrol/guest/locallib.php b/enrol/guest/locallib.php
index 934d47a7e70..65f5a247cd7 100644
--- a/enrol/guest/locallib.php
+++ b/enrol/guest/locallib.php
@@ -14,21 +14,41 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Guest access plugin implementation.
- *
- * @package enrol_guest
- * @copyright 2010 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/formslib.php");
+/**
+ * Guest access plugin implementation.
+ *
+ * @deprecated since Moodle 5.0 - please use {@see enrol_guest\form\enrol_form}
+ *
+ * @package enrol_guest
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+#[\core\attribute\deprecated(replacement: enrol_guest\form\enrol_form::class, since: '5.0', reason: 'Now a dynamic form is used')]
class enrol_guest_enrol_form extends moodleform {
protected $instance;
+ /**
+ * Constructor
+ *
+ * @param mixed $action
+ * @param mixed $customdata
+ * @param string $method
+ * @param string $target
+ * @param mixed $attributes
+ * @param bool $editable
+ * @param array $ajaxformdata
+ */
+ public function __construct($action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true,
+ $ajaxformdata=null) {
+ \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
+ parent::__construct($action, $customdata, $method, $target, $attributes, $editable, $ajaxformdata);
+ }
+
public function definition() {
$mform = $this->_form;
$instance = $this->_customdata;
diff --git a/enrol/guest/tests/behat/guest_access.feature b/enrol/guest/tests/behat/guest_access.feature
index ce8d696b198..f5f6232af04 100644
--- a/enrol/guest/tests/behat/guest_access.feature
+++ b/enrol/guest/tests/behat/guest_access.feature
@@ -30,6 +30,7 @@ Feature: Guest users can auto-enrol themself in courses where guest access is al
When I am on the "Test forum name" "forum activity" page logged in as student1
Then I should not see "Subscribe to this forum"
+ @javascript
Scenario: Allow guest access with password
Given I click on "Edit" "link" in the "Guest access" "table_row"
And I set the following fields to these values:
@@ -38,7 +39,8 @@ Feature: Guest users can auto-enrol themself in courses where guest access is al
And I press "Save changes"
When I am on the "Course 1" course page logged in as student1
Then I should see "Guest access"
+ And I press "Access as a guest"
And I set the following fields to these values:
| Password | moodle_rules |
- And I press "Submit"
+ And I click on "Access as a guest" "button" in the "Guest access" "dialogue"
And I should see "Test forum name"