Merge branch 'MDL-84142' of https://github.com/marinaglancy/moodle into main

This commit is contained in:
Paul Holden
2025-03-13 16:30:37 +00:00
32 changed files with 996 additions and 314 deletions
@@ -0,0 +1,9 @@
issueNumber: MDL-84142
notes:
core_enrol:
- message: >-
Plugins implementing enrol_page_hook() method are encouraged to use the
renderable \core_enrol\output\enrol_page to produce HTML for the
enrolment page. Forms should be displayed in a modal dialogue. See
enrol_self plugin as an example.
type: improved
@@ -0,0 +1,7 @@
issueNumber: MDL-84142
notes:
enrol_self:
- message: >-
Class enrol_self_enrol_form is deprecated, use
enrol_self\form\enrol_form instead
type: deprecated
@@ -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
+2
View File
@@ -40,6 +40,7 @@ Feature: Keyholder role is listed as course contact
And I follow "Course 1"
Then I should see "Keyholder 1"
@javascript
Scenario: Keyholder assigned to a category
Given the following "role assigns" exist:
| user | role | contextlevel | reference |
@@ -50,4 +51,5 @@ Feature: Keyholder role is listed as course contact
When I log in as "student1"
And I am on site homepage
And I follow "Course 1"
And I press "Enrol me"
Then I should see "Keyholder 1"
+70
View File
@@ -0,0 +1,70 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_enrol\output;
use core\output\named_templatable;
use core\output\renderable;
use core\output\single_button;
/**
* Allows to render a widget provided by enrol_plugin::enrol_page_hook()
*
* @package core_enrol
* @copyright Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class enrol_page implements named_templatable, renderable {
/**
* Constructor
*
* @param \stdClass $instance
* @param string|null $header
* @param string|null $body
* @param array $buttons
*/
public function __construct(
/** @var \stdClass */
protected \stdClass $instance,
/** @var string|null */
protected ?string $header = null,
/** @var string|null */
protected ?string $body = null,
/** @var single_button[] */
protected array $buttons = []
) {
}
#[\Override]
public function export_for_template(\core\output\renderer_base $output) {
return [
'enrol' => $this->instance->enrol,
'instanceid' => $this->instance->id,
'header' => $this->header,
'body' => $this->body,
'buttons' => array_map(fn($b) => $b->export_for_template($output), $this->buttons),
'hasbuttons' => !empty($this->buttons),
];
}
#[\Override]
public function get_template_name(\core\output\renderer_base $renderer): string {
return 'core_enrol/enrol_page';
}
}
+48 -53
View File
@@ -24,6 +24,9 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core\output\single_button;
use core_enrol\output\enrol_page;
/**
* Fee enrolment plugin implementation.
*
@@ -172,53 +175,20 @@ class enrol_fee_plugin extends enrol_plugin {
return parent::update_instance($instance, $data);
}
/**
* Creates course enrol form, checks if form submitted
* and enrols user if necessary. It can also redirect.
*
* @param stdClass $instance
* @return string html text, usually a form in a text box
*/
#[\Override]
public function enrol_page_hook(stdClass $instance) {
return $this->show_payment_info($instance);
}
/**
* Returns optional enrolment instance description text.
*
* This is used in detailed course information.
*
*
* @param object $instance
* @return string short html text
*/
public function get_description_text($instance) {
return $this->show_payment_info($instance);
}
/**
* Generates payment information to display on enrol/info page.
*
* @param stdClass $instance
* @return false|string
* @throws coding_exception
* @throws dml_exception
*/
private function show_payment_info(stdClass $instance) {
global $USER, $OUTPUT, $DB;
ob_start();
global $USER, $OUTPUT, $DB, $PAGE;
if ($DB->record_exists('user_enrolments', array('userid' => $USER->id, 'enrolid' => $instance->id))) {
return ob_get_clean();
return '';
}
if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) {
return ob_get_clean();
return '';
}
if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) {
return ob_get_clean();
return '';
}
$course = $DB->get_record('course', array('id' => $instance->courseid));
@@ -230,26 +200,51 @@ class enrol_fee_plugin extends enrol_plugin {
$cost = (float) $instance->cost;
}
$name = !empty($instance->name) ?
format_string($instance->name, true, ['context' => $context]) :
get_string('paymentrequired');
if (abs($cost) < 0.01) { // No cost, other enrolment methods (instances) should be used.
echo '<p>'.get_string('nocost', 'enrol_fee').'</p>';
$notification = new \core\output\notification(get_string('nocost', 'enrol_fee'), 'error', false);
$notification->set_extra_classes(['mb-0']);
$enrolpage = new enrol_page(
instance: $instance,
header: $name,
body: $OUTPUT->render($notification));
return $OUTPUT->render($enrolpage);
} else {
if (isguestuser() || !isloggedin()) {
$button = new single_button(new moodle_url(get_login_url()), get_string('loginsite'),
'get', single_button::BUTTON_PRIMARY);
} else {
$PAGE->requires->js_call_amd('core_payment/gateways_modal', 'init');
$button = new single_button(
$PAGE->url,
get_string('sendpaymentbutton', 'enrol_fee'),
'post',
single_button::BUTTON_PRIMARY,
[
'data-action' => 'core_payment/triggerPayment',
'data-component' => 'enrol_fee',
'data-paymentarea' => 'fee',
'data-itemid' => $instance->id,
'data-cost' => $cost,
'data-successurl' => \enrol_fee\payment\service_provider::get_success_url('fee', $instance->id)->out(false),
'data-description' => get_string('purchasedescription', 'enrol_fee',
format_string($course->fullname, true, ['context' => $context])),
]);
}
$name = !empty($instance->name) ?
format_string($instance->name, true, ['context' => $context]) :
get_string('paymentrequired');
$data = [
'name' => $name,
'isguestuser' => isguestuser() || !isloggedin(),
$body = $OUTPUT->render_from_template('enrol_fee/enrol_page', [
'cost' => \core_payment\helper::get_cost_as_string($cost, $instance->currency),
'instanceid' => $instance->id,
'description' => get_string('purchasedescription', 'enrol_fee',
format_string($course->fullname, true, ['context' => $context])),
'successurl' => \enrol_fee\payment\service_provider::get_success_url('fee', $instance->id)->out(false),
];
echo $OUTPUT->render_from_template('enrol_fee/payment_region', $data);
]);
$enrolpage = new enrol_page(
instance: $instance,
header: $name,
body: $body,
buttons: [$button]);
return $OUTPUT->render($enrolpage);
}
return $OUTPUT->box(ob_get_clean());
}
/**
+30
View File
@@ -0,0 +1,30 @@
{{!
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template enrol_fee/enrol_page
Contents of the enrolment widget on the course enrolment page
Example context (json):
{
"cost": "10.00",
"currency": "USD"
}
}}
<span>
{{#str}} labelvalue, core, {"label": {{#quote}}{{#str}} cost {{/str}}{{/quote}}, "value": {{#quote}}{{cost}}{{/quote}} }{{/str}}
</span>
@@ -1,81 +0,0 @@
{{!
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template enrol_fee/payment_region
This template will render information about course fee along with a button for payment.
Classes required for JS:
* none
Data attributes required for JS:
* data-component
* data-paymentarea
* data-itemid
* data-cost
* data-description
* data-successurl
Context variables required for this template:
* cost - Human readable cost string including amount and currency
* instanceid - Id of the enrolment instance
* description - The description for this purchase
* successurl - The URL of the course
Example context (json):
{
"cost": "$108.50",
"name": "This course requires a payment for entry.",
"instanceid": 11,
"description": "Enrolment in course Introduction to algorithms",
"successurl": "https://moodlesite/course/view.php?id=2",
"isguestuser": false
}
}}
<div class="enrol_fee_payment_region text-center">
{{#isguestuser}}
<div class="mdl-align">
<p>{{{name}}}</p>
<p><b>{{cost}}</b></p>
<p><a href="{{config.wwwroot}}/login/">{{# str }} loginsite {{/ str }}</a></p>
</div>
{{/isguestuser}}
{{^isguestuser}}
<p>{{{name}}}</p>
<p><b>{{cost}}</b></p>
<button
class="btn btn-secondary"
type="button"
id="gateways-modal-trigger-{{ uniqid }}"
data-action="core_payment/triggerPayment"
data-component="enrol_fee"
data-paymentarea="fee"
data-itemid="{{instanceid}}"
data-cost="{{cost}}"
data-successurl="{{successurl}}"
data-description="{{description}}"
>
{{# str }} sendpaymentbutton, enrol_fee {{/ str }}
</button>
{{/isguestuser}}
</div>
{{#js}}
require(['core_payment/gateways_modal'], function(modal) {
modal.init();
});
{{/js}}
+3 -3
View File
@@ -36,7 +36,7 @@ Feature: Signing up for a course with a fee enrolment method
When I log in as "student1"
And I am on course index
And I follow "Course 1"
Then I should see "This course requires a payment for entry."
Then I should see "This course requires a payment for entry"
And I should see "123.45"
And I press "Select payment type"
And I should see "PayPal" in the "Select payment type" "dialogue"
@@ -46,7 +46,7 @@ Feature: Signing up for a course with a fee enrolment method
When I log in as "guest"
And I am on course index
And I follow "Course 1"
Then I should see "This course requires a payment for entry."
Then I should see "This course requires a payment for entry"
And I should see "123.45"
And I should see "Log in to the site"
@@ -66,6 +66,6 @@ Feature: Signing up for a course with a fee enrolment method
When I log in as "student1"
And I am on course index
And I follow "Course 1"
Then I should not see "This course requires a payment for entry."
Then I should not see "This course requires a payment for entry"
Then I should see "Lifetime access"
Then I should not see "Only for teachers"
+10
View File
@@ -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
@@ -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 <http://www.gnu.org/licenses/>.\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"}
+63
View File
@@ -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 <http://www.gnu.org/licenses/>.
/**
* 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();
});
}
}
+150
View File
@@ -0,0 +1,150 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
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]);
}
}
+1
View File
@@ -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<br />
(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';
+41 -36
View File
@@ -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);
}
/**
+27 -7
View File
@@ -14,21 +14,41 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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;
+3 -1
View File
@@ -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"
-46
View File
@@ -1,46 +0,0 @@
<div align="center">
<p><?php print_string("paymentrequired") ?></p>
<p><b><?php echo $instancename; ?></b></p>
<p><b><?php echo get_string("cost").": {$instance->currency} {$localisedcost}"; ?></b></p>
<p><img alt="<?php print_string('paypalaccepted', 'enrol_paypal') ?>" src="https://www.paypal.com/en_US/i/logo/PayPal_mark_60x38.gif" /></p>
<p><?php print_string("paymentinstant") ?></p>
<?php
$paypalurl = empty($CFG->usepaypalsandbox) ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
?>
<form action="<?php echo $paypalurl ?>" method="post">
<input type="hidden" name="cmd" value="_xclick" />
<input type="hidden" name="charset" value="utf-8" />
<input type="hidden" name="business" value="<?php p($this->get_config('paypalbusiness'))?>" />
<input type="hidden" name="item_name" value="<?php p($coursefullname) ?>" />
<input type="hidden" name="item_number" value="<?php p($courseshortname) ?>" />
<input type="hidden" name="quantity" value="1" />
<input type="hidden" name="on0" value="<?php print_string("user") ?>" />
<input type="hidden" name="os0" value="<?php p($userfullname) ?>" />
<input type="hidden" name="custom" value="<?php echo "{$USER->id}-{$course->id}-{$instance->id}" ?>" />
<input type="hidden" name="currency_code" value="<?php p($instance->currency) ?>" />
<input type="hidden" name="amount" value="<?php p($cost) ?>" />
<input type="hidden" name="for_auction" value="false" />
<input type="hidden" name="no_note" value="1" />
<input type="hidden" name="no_shipping" value="1" />
<input type="hidden" name="notify_url" value="<?php echo "$CFG->wwwroot/enrol/paypal/ipn.php"?>" />
<input type="hidden" name="return" value="<?php echo "$CFG->wwwroot/enrol/paypal/return.php?id=$course->id" ?>" />
<input type="hidden" name="cancel_return" value="<?php echo $CFG->wwwroot ?>" />
<input type="hidden" name="rm" value="2" />
<input type="hidden" name="cbt" value="<?php print_string("continuetocourse") ?>" />
<input type="hidden" name="first_name" value="<?php p($userfirstname) ?>" />
<input type="hidden" name="last_name" value="<?php p($userlastname) ?>" />
<input type="hidden" name="address" value="<?php p($useraddress) ?>" />
<input type="hidden" name="city" value="<?php p($usercity) ?>" />
<input type="hidden" name="email" value="<?php p($USER->email) ?>" />
<input type="hidden" name="country" value="<?php p($USER->country) ?>" />
<input type="submit" value="<?php print_string("sendpaymentbutton", "enrol_paypal") ?>" />
</form>
</div>
+66 -46
View File
@@ -24,7 +24,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;
/**
* Paypal enrolment plugin implementation.
@@ -147,84 +148,103 @@ class enrol_paypal_plugin extends enrol_plugin {
return parent::update_instance($instance, $data);
}
/**
* Creates course enrol form, checks if form submitted
* and enrols user if necessary. It can also redirect.
*
* @param stdClass $instance
* @return string html text, usually a form in a text box
*/
function enrol_page_hook(stdClass $instance) {
#[\Override]
public function enrol_page_hook(stdClass $instance) {
global $CFG, $USER, $OUTPUT, $PAGE, $DB;
ob_start();
if ($DB->record_exists('user_enrolments', array('userid'=>$USER->id, 'enrolid'=>$instance->id))) {
return ob_get_clean();
if ($DB->record_exists('user_enrolments', ['userid' => $USER->id, 'enrolid' => $instance->id])) {
return '';
}
if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) {
return ob_get_clean();
return '';
}
if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) {
return ob_get_clean();
return '';
}
$course = $DB->get_record('course', array('id'=>$instance->courseid));
$course = $DB->get_record('course', ['id' => $instance->courseid]);
$context = context_course::instance($course->id);
$shortname = format_string($course->shortname, true, array('context' => $context));
$strloginto = get_string("loginto", "", $shortname);
$strcourses = get_string("courses");
// Pass $view=true to filter hidden caps if the user cannot see them
if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC',
'', '', '', '', false, true)) {
$users = sort_by_roleassignment_authority($users, $context);
$teacher = array_shift($users);
} else {
$teacher = false;
}
if ( (float) $instance->cost <= 0 ) {
$cost = (float) $this->get_config('cost');
} else {
$cost = (float) $instance->cost;
}
if (abs($cost) < 0.01) { // no cost, other enrolment methods (instances) should be used
echo '<p>'.get_string('nocost', 'enrol_paypal').'</p>';
} else {
$name = $this->get_instance_name($instance);
if (abs($cost) < 0.01) {
// No cost, other enrolment methods (instances) should be used.
$notification = new \core\output\notification(get_string('nocost', 'enrol_paypal'), 'error', false);
$notification->set_extra_classes(['mb-0']);
$enrolpage = new enrol_page(
instance: $instance,
header: $name,
body: $OUTPUT->render($notification));
return $OUTPUT->render($enrolpage);
} else {
// Calculate localised and "." cost, make sure we send PayPal the same value,
// please note PayPal expects amount with 2 decimal places and "." separator.
$localisedcost = format_float($cost, 2, true);
$cost = format_float($cost, 2, false);
if (isguestuser()) { // force login only for guest user, not real users with guest role
$wwwroot = $CFG->wwwroot;
echo '<div class="mdl-align"><p>'.get_string('paymentrequired').'</p>';
echo '<p><b>'.get_string('cost').": $instance->currency $localisedcost".'</b></p>';
echo '<p><a href="'.$wwwroot.'/login/">'.get_string('loginsite').'</a></p>';
echo '</div>';
$body = $OUTPUT->render_from_template('enrol_paypal/enrol_page',
['currency' => $instance->currency, 'cost' => $localisedcost]);
if (isguestuser() || !isloggedin()) {
$button = new single_button(new moodle_url(get_login_url()), get_string('loginsite'), 'get',
single_button::BUTTON_PRIMARY);
} else {
//Sanitise some fields before building the PayPal form
$coursefullname = format_string($course->fullname, true, array('context'=>$context));
$courseshortname = $shortname;
// Sanitise some fields before building the PayPal form.
$coursefullname = format_string($course->fullname, true, ['context' => $context]);
$courseshortname = format_string($course->shortname, true, ['context' => $context]);
$userfullname = fullname($USER);
$userfirstname = $USER->firstname;
$userlastname = $USER->lastname;
$useraddress = $USER->address;
$usercity = $USER->city;
$instancename = $this->get_instance_name($instance);
include($CFG->dirroot.'/enrol/paypal/enrol.html');
$buttonurl = new moodle_url(empty($CFG->usepaypalsandbox) ?
'https://www.paypal.com/cgi-bin/webscr' :
'https://www.sandbox.paypal.com/cgi-bin/webscr',
[
'cmd' => '_xclick',
'charset' => 'utf-8',
'business' => $this->get_config('paypalbusiness'),
'item_name' => $coursefullname,
'item_number' => $courseshortname,
'quantity' => 1,
'on0' => get_string("user"),
'os0' => $userfullname,
'custom' => "{$USER->id}-{$course->id}-{$instance->id}",
'currency_code' => $instance->currency,
'amount' => $cost,
'for_auction' => 'false',
'no_note' => 1,
'no_shipping' => 1,
'notify_url' => "$CFG->wwwroot/enrol/paypal/ipn.php",
'return' => "$CFG->wwwroot/enrol/paypal/return.php?id={$course->id}",
'cancel_return' => $CFG->wwwroot,
'rm' => 2,
'cbt' => get_string("continuetocourse"),
'first_name' => $userfirstname,
'last_name' => $userlastname,
'address' => $useraddress,
'city' => $usercity,
'email' => $USER->email,
'country' => $USER->country,
]);
$button = new single_button($buttonurl, get_string("sendpaymentbutton", "enrol_paypal"),
'get', single_button::BUTTON_PRIMARY);
}
$enrolpage = new enrol_page(
instance: $instance,
header: $name,
body: $body,
buttons: [$button]);
return $OUTPUT->render($enrolpage);
}
return $OUTPUT->box(ob_get_clean());
}
/**
@@ -0,0 +1,34 @@
{{!
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template enrol_paypal/enrol_page
Contents of the enrolment widget on the course enrolment page
Example context (json):
{
"cost": "10.00",
"currency": "USD"
}
}}
<div class="d-flex justify-content-between">
<div>{{#str}}cost{{/str}}: {{currency}} {{cost}}</div>
<div>
<img alt={{#quote}}{{#str}}paypalaccepted, enrol_paypal{{/str}}{{/quote}}
src="https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png" >
</div>
</div>
+10
View File
@@ -0,0 +1,10 @@
define("enrol_self/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_self plugin
*
* @module enrol_self/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)("enrol_self",["enrolme"]);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)("enrolme","enrol_self"),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
@@ -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 <http://www.gnu.org/licenses/>.\n\n/**\n * Functions for the enrol_self plugin\n *\n * @module enrol_self/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('enrol_self', [\n 'enrolme',\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('enrolme', 'enrol_self'),\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,aAAc,CAC1B,kBAGEC,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,UAAW,cACrCC,YAAalB,SAIjBM,UAAUH,iBAAiBG,UAAUa,OAAOC,gBAAgBC,QACxDC,OAAOC,SAASC,KAAOH,MAAMI,OAASJ,MAAMI,OACxCC,aAAIC,YAAY,mBAAoB,CAACZ,GAAIf,OAAOU,QAAQK,QAGhET,UAAUsB"}
+63
View File
@@ -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 <http://www.gnu.org/licenses/>.
/**
* Functions for the enrol_self plugin
*
* @module enrol_self/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('enrol_self', [
'enrolme',
]);
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('enrolme', 'enrol_self'),
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();
});
}
}
+204
View File
@@ -0,0 +1,204 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace enrol_self\form;
use core\context\course as context_course;
use core\context\system as context_system;
use core_form\dynamic_form;
use core_text;
use html_writer;
use moodle_url;
/**
* Form for entering password for self enrolment
*
* @package enrol_self
* @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;
/** @var \enrol_self_plugin */
protected $plugin = null;
/**
* Returns the enrolment method
*
* @return \enrol_self_plugin
*/
protected function get_plugin(): \enrol_self_plugin {
global $CFG;
require_once($CFG->dirroot . '/lib/enrollib.php');
if ($this->plugin === null) {
$this->plugin = enrol_get_plugin('self');
}
return $this->plugin;
}
/**
* Returns the instance of the enrolment method
*
* @return \stdClass
*/
protected function get_instance(): \stdClass {
global $DB, $CFG;
require_once($CFG->dirroot . '/lib/enrollib.php');
if ($this->instance === null) {
// Method enrol_get_instances() will also validate that the enrolment method and the instance are enabled.
$courseid = $this->optional_param('id', 0, PARAM_INT);
$instanceid = $this->optional_param('instance', 0, PARAM_INT);
$instances = enrol_get_instances($courseid, true);
$this->instance = $instances[$instanceid] ?? null;
if (empty($this->instance) || $this->instance->enrol !== 'self') {
throw new \moodle_exception('invalidenrolinstance', 'enrol');
}
}
return $this->instance;
}
#[\Override]
public function definition() {
global $USER, $OUTPUT, $CFG;
$mform = $this->_form;
$mform->addElement('password', 'enrolpassword', get_string('password', 'enrol_self'));
// Display keyholders - list of users who have 'enrol/self:holdkey' capability.
$context = context_course::instance($this->instance->courseid);
$userfieldsapi = \core_user\fields::for_userpic();
$ufields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
$keyholders = get_users_by_capability($context, 'enrol/self:holdkey', $ufields);
$keyholdercount = 0;
foreach ($keyholders as $keyholder) {
$keyholdercount++;
if ($keyholdercount === 1) {
$mform->addElement('static', 'keyholder', '', get_string('keyholder', 'enrol_self'));
}
if ($USER->id == $keyholder->id
|| has_capability('moodle/user:viewdetails', context_system::instance())
|| has_coursecontact_role($keyholder->id)) {
$profileurl = new moodle_url('/user/profile.php', ['id' => $keyholder->id, 'course' => $this->instance->courseid]);
$profilelink = html_writer::link($profileurl, fullname($keyholder));
} else {
$profilelink = fullname($keyholder);
}
$profilepic = $OUTPUT->user_picture($keyholder, ['size' => 35, 'courseid' => $this->instance->courseid]);
$mform->addElement('static', 'keyholder' . $keyholdercount, '', $profilepic . $profilelink);
}
$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;
require_once($CFG->dirroot.'/enrol/self/locallib.php');
$errors = parent::validation($data, $files);
$instance = $this->get_instance();
if ($data['enrolpassword'] !== $instance->password) {
if ($instance->customint1) {
// 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');
}
} else {
$plugin = enrol_get_plugin('self');
if ($plugin->get_config('showhint')) {
$hint = core_text::substr($instance->password, 0, 1);
$errors['enrolpassword'] = get_string('passwordinvalidhint', 'enrol_self', $hint);
} else {
$errors['enrolpassword'] = get_string('passwordinvalid', 'enrol_self');
}
}
}
return $errors;
}
#[\Override]
protected function check_access_for_dynamic_submission(): void {
global $USER, $CFG;
$instance = $this->get_instance();
$courseid = $instance->courseid;
$course = get_course($courseid);
$context = context_course::instance($instance->courseid);
if (!\core_course_category::can_view_course_info($course) && !is_enrolled($context, $USER, '', true)) {
throw new \moodle_exception('coursehidden', '', $CFG->wwwroot . '/');
}
if (isguestuser()) {
throw new \moodle_exception('noguestaccess', 'enrol');
}
$canselfenrol = $this->get_plugin()->can_self_enrol($instance);
if ($canselfenrol !== true) {
throw new \moodle_exception($canselfenrol);
}
if (!$instance->password) {
throw new \moodle_exception('nopassword', 'enrol_self');
}
}
#[\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 $CFG, $SESSION;
$this->get_plugin()->enrol_self($this->get_instance(), $this->get_data());
// 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($this->get_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]);
}
}
+1
View File
@@ -36,6 +36,7 @@ $string['editselectedusers'] = 'Edit selected user enrolments';
$string['enrolenddate'] = 'End date';
$string['enrolenddate_help'] = 'If enabled, users can enrol themselves until this date only.';
$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date';
$string['enrolkeyrequired'] = 'An enrolment key will be required';
$string['enrolme'] = 'Enrol me';
$string['enrolperiod'] = 'Enrolment duration';
$string['enrolperiod_desc'] = 'Default length of time that the enrolment is valid. If set to zero, the enrolment duration will be unlimited by default.';
+50 -33
View File
@@ -22,6 +22,9 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core\output\single_button;
use core_enrol\output\enrol_page;
/**
* Self enrolment plugin implementation.
* @author Petr Skoda
@@ -164,7 +167,6 @@ class enrol_self_plugin extends enrol_plugin {
*
* @param stdClass $instance enrolment instance
* @param stdClass $data data needed for enrolment.
* @return bool|array true if enroled else eddor code and messege
*/
public function enrol_self(stdClass $instance, $data = null) {
global $DB, $USER, $CFG;
@@ -202,46 +204,61 @@ class enrol_self_plugin extends enrol_plugin {
}
}
/**
* Creates course enrol form, checks if form submitted
* and enrols user if necessary. It can also redirect.
*
* @param stdClass $instance
* @return string html text, usually a form in a text box
*/
#[\Override]
public function enrol_page_hook(stdClass $instance) {
global $CFG, $OUTPUT, $USER;
global $CFG, $OUTPUT, $USER, $PAGE;
require_once("$CFG->dirroot/enrol/self/locallib.php");
$buttonurl = null;
$buttontext = '';
$buttonattrs = [];
$body = '';
$title = $this->get_instance_name($instance);
$enrolstatus = $this->can_self_enrol($instance);
if (true === $enrolstatus) {
// This user can self enrol using this instance.
$form = new enrol_self_enrol_form(null, $instance);
$instanceid = optional_param('instance', 0, PARAM_INT);
if ($instance->id == $instanceid) {
if ($data = $form->get_data()) {
$this->enrol_self($instance, $data);
if ($enrolstatus === true) {
if ($instance->password) {
// Self-enrolment with password. Display a button to open a form in a modal.
$body = get_string('enrolkeyrequired', 'enrol_self');
$buttonurl = $PAGE->url;
$buttonattrs = [
'data-id' => $instance->courseid,
'data-instance' => $instance->id,
'data-form' => enrol_self\form\enrol_form::class,
'data-title' => $title,
];
$PAGE->requires->js_call_amd('enrol_self/enrol_page', 'initEnrol', [$instance->id]);
} else {
// Self-enrolment without password. Display a button to self enrol. If button is pressed - enrol the user.
if (optional_param('action', null, PARAM_TEXT) === 'enrol' && confirm_sesskey()) {
$this->enrol_self($instance, (object)[]);
return '';
}
$body = get_string('nopassword', 'enrol_self');
$buttonurl = new moodle_url($PAGE->url, ['action' => 'enrol', 'sesskey' => sesskey()]);
}
$buttontext = get_string('enrolme', 'enrol_self');
} else if (isguestuser()) {
// User is not logged in. Display a button to login.
$buttonurl = new moodle_url(get_login_url());
$body = get_string('noguestaccess', 'enrol');
$buttontext = get_string('continue');
} else if (!$enrolstatus) {
// No reason why user can not use this method, do not display anything.
return '';
} else {
// This user can not self enrol using this instance. Using an empty form to keep
// the UI consistent with other enrolment plugins that returns a form.
$data = new stdClass();
$data->header = $this->get_instance_name($instance);
$data->info = $enrolstatus;
// The can_self_enrol call returns a button to the login page if the user is a
// guest, setting the login url to the form if that is the case.
$url = isguestuser() ? get_login_url() : null;
$form = new enrol_self_empty_form($url, $data);
$body = $enrolstatus;
}
ob_start();
$form->display();
$output = ob_get_clean();
return $OUTPUT->box($output);
$notification = new \core\output\notification($body, 'info', false);
$notification->set_extra_classes(['mb-0']);
$enrolpage = new enrol_page(
instance: $instance,
header: $title,
body: $OUTPUT->render($notification),
buttons: $buttonurl ?
[new single_button($buttonurl, $buttontext, 'get', single_button::BUTTON_PRIMARY, $buttonattrs)] :
[]);
return $OUTPUT->render($enrolpage);
}
/**
@@ -285,7 +302,7 @@ class enrol_self_plugin extends enrol_plugin {
* This function doesn't check user capabilities. Use can_self_enrol to check capabilities.
*
* @param stdClass $instance enrolment instance
* @return bool - true means "Enrol me in this course" link could be available
* @return bool|string - true means "Enrol me in this course" link could be available
*/
public function is_self_enrol_available(stdClass $instance) {
global $CFG, $DB, $USER;
+23
View File
@@ -53,10 +53,33 @@ function enrol_self_check_group_enrolment_key($courseid, $enrolpassword) {
return $found;
}
/**
* Old class for displaying the self enrolment form
*
* @deprecated since Moodle 5.0 - please use {@see enrol_self\form\enrol_form}
*/
#[\core\attribute\deprecated(replacement: enrol_self\form\enrol_form::class, since: '5.0', reason: 'Now a dynamic form is used')]
class enrol_self_enrol_form extends moodleform {
protected $instance;
protected $toomany = false;
/**
* 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);
}
/**
* Overriding this function to get unique form id for multiple self enrolments.
*
+3 -1
View File
@@ -34,11 +34,13 @@ Feature: Users can be defined as key holders in courses where self enrolment is
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I should see "An enrolment key will be required"
And I press "Enrol me"
And I should see "You should have received this enrolment key from:"
And I should see "Manager 1"
And I set the following fields to these values:
| Enrolment key | moodle_rules |
And I press "Enrol me"
And I click on "Enrol me" "button" in the "Test student enrolment" "dialogue"
Then I should see "New section"
And I should not see "Enrolment options"
And I should not see "Enrol me in this course"
@@ -42,6 +42,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
Then I should see "New section"
And I should not see "Enrolment options"
@javascript
Scenario: Self-enrolment enabled requiring an enrolment key
Given I log in as "teacher1"
When I add "Self enrolment" enrolment method in "Course 1" with:
@@ -50,9 +51,11 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I should see "An enrolment key will be required"
And I press "Enrol me"
And I set the following fields to these values:
| Enrolment key | moodle_rules |
And I press "Enrol me"
And I click on "Enrol me" "button" in the "Test student enrolment" "dialogue"
Then I should see "New section"
And I should not see "Enrolment options"
And I should not see "Enrol me in this course"
@@ -62,6 +65,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
When I am on "Course 1" course homepage
Then I should see "You cannot enrol yourself in this course"
@javascript
Scenario: Self-enrolment enabled requiring a group enrolment key
Given I log in as "teacher1"
When I add "Self enrolment" enrolment method in "Course 1" with:
@@ -77,16 +81,18 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
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 set the following fields to these values:
| Enrolment key | Test-groupenrolkey1 |
And I press "Enrol me"
And I click on "Enrol me" "button" in the "Test student enrolment" "dialogue"
Then I should see "New section"
And I should not see "Enrolment options"
And I should not see "Enrol me in this course"
And I am on the "Course 1" course page logged in as student2
And I press "Enrol me"
And I set the following fields to these values:
| Enrolment key | moodle_rules |
And I press "Enrol me"
And I click on "Enrol me" "button" in the "Test student enrolment" "dialogue"
And I am on the "Course 1" course page logged in as teacher1
And I navigate to course participants
And the following should exist in the "participants" table:
+52
View File
@@ -0,0 +1,52 @@
{{!
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template core_enrol/enrol_page
Recommended template for displaying the enrolment plugin call-to-action on the enrol/index.php page
Usually to be used with the \core_enrol\output\enrol_page and returned from the enrol_plugin::enrol_page_hook()
Example context (json):
{
"enrol": "self",
"instanceid": 1,
"header": "Self-enrolment",
"body": "You can enrol yourself in this course.",
"hasbuttons": true,
"buttons": [{
"method" : "get",
"id": "buttonid-123",
"type": "primary",
"url" : "#",
"label" : "Enrol me"
}]
}
}}
<div class="box generalbox mb-3 enrol-instance" data-enrol="{{enrol}}" data-instanceid="{{instanceid}}">
<div class="card">
{{#header}}<div class="card-header"><h3 class="mb-0">{{{header}}}</h3></div>{{/header}}
<div class="card-body">{{{body}}}</div>
{{#hasbuttons}}
<div class="card-footer">
{{#buttons}}
{{> core/single_button }}
{{/buttons}}
</div>
{{/hasbuttons}}
</div>
</div>
+1 -1
View File
@@ -1658,7 +1658,7 @@ $string['pathnotexists'] = 'Path doesn\'t exist in your server!';
$string['pathslasherror'] = 'Path can\'t end with a slash!!';
$string['paymentinstant'] = 'Use the button below to pay and be enrolled within minutes!';
$string['paymentpending'] = '(<small><b><u>{$a}</u></b> pending</small>)';
$string['paymentrequired'] = 'This course requires a payment for entry.';
$string['paymentrequired'] = 'This course requires a payment for entry';
$string['payments'] = 'Payments';
$string['paymentsorry'] = 'Thank you for your payment! Unfortunately your payment has not yet been fully processed, and you are not yet registered to enter the course "{$a->fullname}". Please try continuing to the course in a few seconds, but if you continue to have trouble then please alert the {$a->teacher} or the site administrator';
$string['paymentthanks'] = 'Thank you for your payment! You are now enrolled in your course:<br />"{$a}"';
+7 -3
View File
@@ -2793,11 +2793,15 @@ abstract class enrol_plugin {
}
/**
* Creates course enrol form, checks if form submitted
* and enrols user if necessary. It can also redirect.
* Creates a widget to display on the course enrolment page. It can also redirect.
*
* It is recommended that all plugins use the same template for the consistent output. Example:
*
* $obj = new \core_enrol\output\enrol_page($instance, ...);
* return $OUTPUT->render($obj);
*
* @param stdClass $instance
* @return string html text, usually a form in a text box
* @return string|null html to display on the enrolment page
*/
public function enrol_page_hook(stdClass $instance) {
return null;