diff --git a/enrol/self/lib.php b/enrol/self/lib.php index 1252b060132..a125a4c1272 100644 --- a/enrol/self/lib.php +++ b/enrol/self/lib.php @@ -231,7 +231,7 @@ class enrol_self_plugin extends enrol_plugin { * @return bool|string true if successful, else error message or false. */ public function can_self_enrol(stdClass $instance, $checkuserenrolment = true) { - global $CFG, $DB, $OUTPUT, $USER; + global $DB, $OUTPUT, $USER; if ($checkuserenrolment) { if (isguestuser()) { @@ -244,8 +244,10 @@ class enrol_self_plugin extends enrol_plugin { } } - if ($instance->status != ENROL_INSTANCE_ENABLED) { - return get_string('canntenrol', 'enrol_self'); + // Check if self enrolment is available right now for users. + $result = $this->is_self_enrol_available($instance); + if ($result !== true) { + return $result; } // Check if user has the capability to enrol in this context. @@ -253,6 +255,23 @@ class enrol_self_plugin extends enrol_plugin { return get_string('canntenrol', 'enrol_self'); } + return true; + } + + /** + * Does this plugin support some way to self enrol? + * 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 + */ + public function is_self_enrol_available(stdClass $instance) { + global $CFG, $DB, $USER; + + if ($instance->status != ENROL_INSTANCE_ENABLED) { + return get_string('canntenrol', 'enrol_self'); + } + if ($instance->enrolstartdate != 0 and $instance->enrolstartdate > time()) { return get_string('canntenrolearly', 'enrol_self', userdate($instance->enrolstartdate)); } diff --git a/enrol/self/tests/self_test.php b/enrol/self/tests/self_test.php index 99deb277c24..600c1ba10a3 100644 --- a/enrol/self/tests/self_test.php +++ b/enrol/self/tests/self_test.php @@ -630,6 +630,137 @@ class self_test extends \advanced_testcase { $this->assertSame($expectederrorstring, $selfplugin->can_self_enrol($instance1, true)); } + /** + * Test is_self_enrol_available function behavior. + * + * @covers ::is_self_enrol_available + */ + public function test_is_self_enrol_available() { + global $DB, $CFG; + + $this->resetAfterTest(); + $this->preventResetByRollback(); // Messaging does not like transactions... + + $selfplugin = enrol_get_plugin('self'); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + + $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); + $course = $this->getDataGenerator()->create_course(); + $cohort1 = $this->getDataGenerator()->create_cohort(); + $cohort2 = $this->getDataGenerator()->create_cohort(); + + // New enrolments are allowed and enrolment instance is enabled. + $instance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'self'], '*', MUST_EXIST); + $instance->customint6 = 1; + $DB->update_record('enrol', $instance); + $selfplugin->update_status($instance, ENROL_INSTANCE_ENABLED); + $this->setUser($user1); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + + $canntenrolerror = get_string('canntenrol', 'enrol_self'); + + // New enrolments are not allowed, but enrolment instance is enabled. + $instance->customint6 = 0; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + + // New enrolments are allowed, but enrolment instance is disabled. + $instance->customint6 = 1; + $DB->update_record('enrol', $instance); + $selfplugin->update_status($instance, ENROL_INSTANCE_DISABLED); + $this->setUser($user1); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + + // New enrolments are not allowed and enrolment instance is disabled. + $instance->customint6 = 0; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + + // Enable enrolment instance for the rest of the tests. + $selfplugin->update_status($instance, ENROL_INSTANCE_ENABLED); + + // Enrol start date is in future. + $instance->customint6 = 1; + $instance->enrolstartdate = time() + 60; + $DB->update_record('enrol', $instance); + $error = get_string('canntenrolearly', 'enrol_self', userdate($instance->enrolstartdate)); + $this->setUser($user1); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + + // Enrol start date is in past. + $instance->enrolstartdate = time() - 60; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + + // Enrol end date is in future. + $instance->enrolstartdate = 0; + $instance->enrolenddate = time() + 60; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + + // Enrol end date is in past. + $instance->enrolenddate = time() - 60; + $DB->update_record('enrol', $instance); + $error = get_string('canntenrollate', 'enrol_self', userdate($instance->enrolenddate)); + $this->setUser($user1); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + + // Maximum enrolments reached. + $instance->customint3 = 1; + $instance->enrolenddate = 0; + $DB->update_record('enrol', $instance); + $selfplugin->enrol_user($instance, $user2->id, $studentrole->id); + $error = get_string('maxenrolledreached', 'enrol_self'); + $this->setUser($user1); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertEquals($error, $selfplugin->is_self_enrol_available($instance)); + + // Maximum enrolments not reached. + $instance->customint3 = 3; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertTrue($selfplugin->is_self_enrol_available($instance)); + + require_once("$CFG->dirroot/cohort/lib.php"); + cohort_add_member($cohort1->id, $user2->id); + + // Cohort test. + $instance->customint5 = $cohort1->id; + $DB->update_record('enrol', $instance); + $error = get_string('cohortnonmemberinfo', 'enrol_self', $cohort1->name); + $this->setUser($user1); + $this->assertStringContainsString($error, $selfplugin->is_self_enrol_available($instance)); + $this->setGuestUser(); + $this->assertStringContainsString($error, $selfplugin->is_self_enrol_available($instance)); + $this->setUser($user2); + $this->assertEquals($canntenrolerror, $selfplugin->is_self_enrol_available($instance)); + } + /** * Test enrol_self_check_group_enrolment_key */ diff --git a/enrol/tests/enrollib_test.php b/enrol/tests/enrollib_test.php index 2f1d91404ff..f033f57e208 100644 --- a/enrol/tests/enrollib_test.php +++ b/enrol/tests/enrollib_test.php @@ -1581,4 +1581,134 @@ class enrollib_test extends advanced_testcase { $this->assertTrue((int)$secondrun > (int)$firstrun); } + /** + * Test enrol_selfenrol_available function behavior. + * + * @covers ::enrol_selfenrol_available + */ + public function test_enrol_selfenrol_available() { + global $DB, $CFG; + + $this->resetAfterTest(); + $this->preventResetByRollback(); // Messaging does not like transactions... + + $selfplugin = enrol_get_plugin('self'); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + + $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); + $course = $this->getDataGenerator()->create_course(); + $cohort1 = $this->getDataGenerator()->create_cohort(); + $cohort2 = $this->getDataGenerator()->create_cohort(); + + // New enrolments are allowed and enrolment instance is enabled. + $instance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'self'], '*', MUST_EXIST); + $instance->customint6 = 1; + $DB->update_record('enrol', $instance); + $selfplugin->update_status($instance, ENROL_INSTANCE_ENABLED); + $this->setUser($user1); + $this->assertTrue(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertTrue(enrol_selfenrol_available($course->id)); + + $canntenrolerror = get_string('canntenrol', 'enrol_self'); + + // New enrolments are not allowed, but enrolment instance is enabled. + $instance->customint6 = 0; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // New enrolments are allowed, but enrolment instance is disabled. + $instance->customint6 = 1; + $DB->update_record('enrol', $instance); + $selfplugin->update_status($instance, ENROL_INSTANCE_DISABLED); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // New enrolments are not allowed and enrolment instance is disabled. + $instance->customint6 = 0; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // Enable enrolment instance for the rest of the tests. + $selfplugin->update_status($instance, ENROL_INSTANCE_ENABLED); + + // Enrol start date is in future. + $instance->customint6 = 1; + $instance->enrolstartdate = time() + 60; + $DB->update_record('enrol', $instance); + $error = get_string('canntenrolearly', 'enrol_self', userdate($instance->enrolstartdate)); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // Enrol start date is in past. + $instance->enrolstartdate = time() - 60; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertTrue(enrol_selfenrol_available($course->id)); + + // Enrol end date is in future. + $instance->enrolstartdate = 0; + $instance->enrolenddate = time() + 60; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertTrue(enrol_selfenrol_available($course->id)); + + // Enrol end date is in past. + $instance->enrolenddate = time() - 60; + $DB->update_record('enrol', $instance); + $error = get_string('canntenrollate', 'enrol_self', userdate($instance->enrolenddate)); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // Maximum enrolments reached. + $instance->customint3 = 1; + $instance->enrolenddate = 0; + $DB->update_record('enrol', $instance); + $selfplugin->enrol_user($instance, $user2->id, $studentrole->id); + $error = get_string('maxenrolledreached', 'enrol_self'); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + + // Maximum enrolments not reached. + $instance->customint3 = 3; + $DB->update_record('enrol', $instance); + $this->setUser($user1); + $this->assertTrue(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertTrue(enrol_selfenrol_available($course->id)); + + require_once("$CFG->dirroot/cohort/lib.php"); + cohort_add_member($cohort1->id, $user2->id); + + // Cohort test. + $instance->customint5 = $cohort1->id; + $DB->update_record('enrol', $instance); + $error = get_string('cohortnonmemberinfo', 'enrol_self', $cohort1->name); + $this->setUser($user1); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setGuestUser(); + $this->assertFalse(enrol_selfenrol_available($course->id)); + $this->setUser($user2); + $this->assertFalse(enrol_selfenrol_available($course->id)); + } } diff --git a/enrol/upgrade.txt b/enrol/upgrade.txt index cc7d5eb806a..3ac64afd31d 100644 --- a/enrol/upgrade.txt +++ b/enrol/upgrade.txt @@ -1,6 +1,10 @@ This files describes API changes in /enrol/* - plugins, information provided here is intended especially for developers. +=== 4.2 === + +* New is_self_enrol_available() function has been created. Similar to can_self_enrol but without checking user capabilities. + === 4.0 === * Final deprecation of the following webservice: diff --git a/lib/enrollib.php b/lib/enrollib.php index 8f1cb302cac..62d984bd70a 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -1235,7 +1235,12 @@ function enrol_selfenrol_available($courseid) { if ($instance->enrol === 'guest') { continue; } - if ($plugins[$instance->enrol]->show_enrolme_link($instance)) { + if ((isguestuser() || !isloggedin()) && + ($plugins[$instance->enrol]->is_self_enrol_available($instance) === true)) { + $result = true; + break; + } + if ($plugins[$instance->enrol]->show_enrolme_link($instance) === true) { $result = true; break; } @@ -2011,6 +2016,17 @@ abstract class enrol_plugin { return false; } + /** + * Does this plugin support some way to self enrol? + * 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. + */ + public function is_self_enrol_available(stdClass $instance) { + return false; + } + /** * Attempt to automatically enrol current user in course without any interaction, * calling code has to make sure the plugin and instance are active. diff --git a/mod/forum/templates/discussion_list.mustache b/mod/forum/templates/discussion_list.mustache index 1758dcd289b..bc379943683 100644 --- a/mod/forum/templates/discussion_list.mustache +++ b/mod/forum/templates/discussion_list.mustache @@ -62,13 +62,13 @@ {{/forum.capabilities.create}} {{^forum.capabilities.create}} {{#forum.capabilities.selfenrol}} -
+ {{#enablediscussioncreation}} {{$discussion_create_text}} {{#str}}addanewdiscussion, forum{{/str}} {{/discussion_create_text}} -
+ {{/enablediscussioncreation}} {{/forum.capabilities.selfenrol}} {{/forum.capabilities.create}} {{#forum.capabilities.grade}} diff --git a/mod/forum/templates/forum_new_discussion_actionbar.mustache b/mod/forum/templates/forum_new_discussion_actionbar.mustache index 2f561b227ce..c9049bc3df8 100644 --- a/mod/forum/templates/forum_new_discussion_actionbar.mustache +++ b/mod/forum/templates/forum_new_discussion_actionbar.mustache @@ -47,3 +47,10 @@ {{#str}}addanewdiscussion, forum{{/str}} {{/forum.capabilities.create}} +{{^forum.capabilities.create}} + {{#forum.capabilities.selfenrol}} + + {{#str}}addanewdiscussion, forum{{/str}} + + {{/forum.capabilities.selfenrol}} +{{/forum.capabilities.create}} diff --git a/mod/forum/tests/behat/guest_users.feature b/mod/forum/tests/behat/guest_users.feature new file mode 100644 index 00000000000..14402630c63 --- /dev/null +++ b/mod/forum/tests/behat/guest_users.feature @@ -0,0 +1,143 @@ +@mod @mod_forum @javascript +Feature: Guest and not logged users could see the option to add new post or reply + In order to guide users to create an account + As a guest or not logged user + I want to see the option to add new post or reply + + Background: + Given the following config values are set as admin: + | enrol_guest | Yes | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher | Teacher | 1 | teacher@example.com | + And the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | teacher | C1 | editingteacher | + And I am on the "Course 1" "enrolment methods" page logged in as teacher + And I click on "Enable" "link" in the "Guest access" "table_row" + + Scenario Outline: As a not enrolled guest I don't see the option to add a new discussion + Given the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum | C1 | forum | | + And I add a new discussion to "Forum" forum with: + | Subject | Forum discussion 1 | + | Message | How awesome is this forum discussion? | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum" "forum activity" page + Then I should not see "Add discussion topic" + And I should see "Forum discussion 1" + And I click on "Forum discussion 1" "link" + And I should not see "Reply" + + Examples: + | type | + | general | + | eachuser | + | qanda | + + Scenario: As a not enrolled guest I don't see the option to add a new discussion in a single forum + Given the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum (single discussion) | C1 | forum | single | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum (single discussion)" "forum activity" page + Then I should not see "Add discussion topic" + And I should see "Forum (single discussion)" + And I should not see "Reply" + + Scenario: As a not enrolled guest I don't see the option to add a new discussion in a blog type forum + Given the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum | C1 | forum | blog | + And I add a new discussion to "Forum" forum with: + | Subject | Forum discussion 1 | + | Message | How awesome is this forum discussion? | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum" "forum activity" page + Then I should not see "Add discussion topic" + And I should see "Forum discussion 1" + And I should not see "Reply" + + Scenario Outline: As an enrolled guest I see the option to add a new discussion + Given I am on the "Course 1" "enrolment methods" page logged in as teacher + And I click on "Enable" "link" in the "Self enrolment" "table_row" + And the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum | C1 | forum | | + And I add a new discussion to "Forum" forum with: + | Subject | Forum discussion 1 | + | Message | How awesome is this forum discussion? | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum" "forum activity" page + Then I should see "Add discussion topic" + And I click on "Add discussion topic" "link" + And I should see "Sorry, guests are not allowed to post" + And I click on "Cancel" "button" + And I should see "Forum discussion 1" + And I click on "Forum discussion 1" "link" + And I should see "Reply" + And I click on "Reply" "link" + And I should see "Sorry, guests are not allowed to post" + And I click on "Continue" "button" + And I should see "Log in" + + Examples: + | type | + | general | + | eachuser | + | qanda | + + Scenario: As an enrolled guest I see the option to reply in a single forum + Given I am on the "Course 1" "enrolment methods" page logged in as teacher + And I click on "Enable" "link" in the "Self enrolment" "table_row" + And the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum (single discussion) | C1 | forum | single | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum (single discussion)" "forum activity" page + And I should see "Forum (single discussion)" + Then I should see "Reply" + And I click on "Reply" "link" + And I should see "Sorry, guests are not allowed to post" + And I click on "Cancel" "button" + And I should see "Reply" + And I click on "Reply" "link" + And I click on "Continue" "button" + And I should see "Log in" + + Scenario: As an enrolled guest I see the option to reply in a blog type forum + Given I am on the "Course 1" "enrolment methods" page logged in as teacher + And I click on "Enable" "link" in the "Self enrolment" "table_row" + And the following "activities" exist: + | activity | name | course | idnumber | type | + | forum | Forum | C1 | forum | blog | + And I add a new discussion to "Forum" forum with: + | Subject | Forum discussion 1 | + | Message | How awesome is this forum discussion? | + And I log out + And I am on "Course 1" course homepage + When I press "Log in as a guest" + And I am on the "Forum" "forum activity" page + Then I should see "Add discussion topic" + And I click on "Add discussion topic" "link" + And I should see "Sorry, guests are not allowed to post" + And I click on "Cancel" "button" + And I should see "Forum discussion 1" + And I click on "Add discussion topic" "link" + And I should see "Sorry, guests are not allowed to post" + And I click on "Continue" "button" + And I should see "Log in"