diff --git a/lib/classes/user.php b/lib/classes/user.php index 4e5de0f6855..774d5a807f0 100644 --- a/lib/classes/user.php +++ b/lib/classes/user.php @@ -1134,4 +1134,39 @@ class core_user { } } + /** + * Is the user expected to perform an action to start using Moodle properly? + * + * This covers cases such as filling the profile, changing password or agreeing to the site policy. + * + * @param stdClass $user User object, defaults to the current user. + * @return bool + */ + public static function awaiting_action(stdClass $user = null): bool { + global $USER; + + if ($user === null) { + $user = $USER; + } + + if (user_not_fully_set_up($user)) { + // Awaiting the user to fill all fields in the profile. + return true; + } + + if (get_user_preferences('auth_forcepasswordchange', false, $user)) { + // Awaiting the user to change their password. + return true; + } + + if (empty($user->policyagreed) && !is_siteadmin($user)) { + $manager = new \core_privacy\local\sitepolicy\manager(); + + if ($manager->is_defined(isguestuser($user))) { + return true; + } + } + + return false; + } } diff --git a/lib/tests/user_test.php b/lib/tests/user_test.php index e93eac3b6af..0b9f1d91aa2 100644 --- a/lib/tests/user_test.php +++ b/lib/tests/user_test.php @@ -770,4 +770,53 @@ class core_user_testcase extends advanced_testcase { $this->assertFalse(\core_user::is_real_user(core_user::get_support_user()->id, true)); } + /** + * Tests for the {@see \core_user::awaiting_action()} method. + */ + public function test_awaiting_action() { + global $CFG, $DB, $USER; + + $guest = \core_user::get_user($CFG->siteguest); + $student = $this->getDataGenerator()->create_user(); + $teacher = $this->getDataGenerator()->create_user(); + $manager = $this->getDataGenerator()->create_user(); + $admin = get_admin(); + + $this->getDataGenerator()->role_assign($DB->get_field('role', 'id', ['shortname' => 'manager']), + $manager->id, \context_system::instance()->id); + + // Scenario: Guests required to agree to site policy. + $this->assertFalse(\core_user::awaiting_action($guest)); + + $CFG->sitepolicyguest = 'https://example.com'; + $this->assertTrue(\core_user::awaiting_action($guest)); + + $guest->policyagreed = 1; + $this->assertFalse(\core_user::awaiting_action($guest)); + + // Scenario: Student required to fill their profile. + $this->assertFalse(\core_user::awaiting_action($student)); + + $student->firstname = ''; + $this->assertTrue(\core_user::awaiting_action($student)); + + $student->firstname = 'Alice'; + $this->assertFalse(\core_user::awaiting_action($student)); + + // Scenario: Teacher force to change their password. + $this->assertFalse(\core_user::awaiting_action($teacher)); + + set_user_preference('auth_forcepasswordchange', 1, $teacher); + $this->assertTrue(\core_user::awaiting_action($teacher)); + + unset_user_preference('auth_forcepasswordchange', $teacher); + $this->assertFalse(\core_user::awaiting_action($teacher)); + + // Scenario: Admins do not need to agree to the policy but others do. + $this->assertFalse(\core_user::awaiting_action($admin)); + $this->assertFalse(\core_user::awaiting_action($manager)); + $CFG->sitepolicy = 'https://example.com'; + $this->assertFalse(\core_user::awaiting_action($admin)); + $this->assertTrue(\core_user::awaiting_action($manager)); + } } diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 2ba9d7d7497..77f88aad2f0 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -58,6 +58,9 @@ information provided here is intended especially for developers. completion_info::internal_set_data() to reaggregate completions that have been marked for instant course completion. * The following functions have been finally deprecated and can not be used anymore: - generate_uuid +* New method \core_user::awaiting_action() has been introduced to check if the user is fully ready to use the site or + whether there is an action (such as filling the missing profile field, changing password or agreeing to the site + policy) needed. === 3.11.2 === * For security reasons, filelib has been updated so all requests now use emulated redirects.