diff --git a/public/admin/tool/mfa/classes/manager.php b/public/admin/tool/mfa/classes/manager.php index 74e9ca7216a..ab557b6f796 100644 --- a/public/admin/tool/mfa/classes/manager.php +++ b/public/admin/tool/mfa/classes/manager.php @@ -51,8 +51,49 @@ class manager { 'tool_mfa' => [ 'guidance', ], + 'theme_*' => [ + 'loginbackgroundimage', + ], ]; + /** + * Returns allowed fileareas for a component. + * + * Supports exact component matches and wildcard suffix matches such as `theme_*`. + * + * @param string $component the component to check. + * @return array|null the allowed fileareas, or null if the component is not allowed. + */ + protected static function get_allowed_fileareas_for_component(string $component): ?array { + if (array_key_exists($component, static::ALLOWED_COMPONENTS)) { + return static::ALLOWED_COMPONENTS[$component]; + } + + foreach (static::ALLOWED_COMPONENTS as $pattern => $fileareas) { + if (!str_ends_with($pattern, '*')) { + continue; + } + + $prefix = substr($pattern, 0, -1); + if ($prefix !== '' && str_starts_with($component, $prefix)) { + return $fileareas; + } + } + + return null; + } + + /** + * Checks whether a filearea is allowed. + * + * @param string $filearea the filearea to check. + * @param array $allowedfileareas the allowed fileareas for the component, where '*' allows all fileareas. + * @return bool + */ + protected static function is_allowed_filearea(string $filearea, array $allowedfileareas): bool { + return in_array('*', $allowedfileareas) || in_array($filearea, $allowedfileareas); + } + /** * Displays a debug table with current factor information. * @@ -469,13 +510,15 @@ class manager { $component = clean_param(array_shift($args), PARAM_COMPONENT); $filearea = clean_param(array_shift($args), PARAM_AREA); + $allowedfileareas = static::get_allowed_fileareas_for_component($component); + // Check allowed components. - if (!array_key_exists($component, static::ALLOWED_COMPONENTS)) { + if ($allowedfileareas === null) { return self::REDIRECT; } // Check allowed fileareas. - if (!in_array($filearea, static::ALLOWED_COMPONENTS[$component])) { + if (!static::is_allowed_filearea($filearea, $allowedfileareas)) { return self::REDIRECT; } diff --git a/public/admin/tool/mfa/tests/manager_test.php b/public/admin/tool/mfa/tests/manager_test.php index 16e97565198..35f856e3f9a 100644 --- a/public/admin/tool/mfa/tests/manager_test.php +++ b/public/admin/tool/mfa/tests/manager_test.php @@ -277,6 +277,14 @@ final class manager_test extends \advanced_testcase { $guideurl = new \moodle_url('/pluginfile.php/1/tool_mfa/guidance/0/capybara.png'); $this->assertEquals(\tool_mfa\manager::NO_REDIRECT, \tool_mfa\manager::should_require_mfa($guideurl, false)); + // Access the allowed theme pluginfile area via wildcard component rules. + $themeurl = new \moodle_url('/pluginfile.php/1/theme_boost/loginbackgroundimage/0/background.jpg'); + $this->assertEquals(\tool_mfa\manager::NO_REDIRECT, \tool_mfa\manager::should_require_mfa($themeurl, false)); + + // Access a different theme pluginfile area which is not explicitly allowed. + $themeurl = new \moodle_url('/pluginfile.php/1/theme_classic/customfield/0/example.txt'); + $this->assertEquals(\tool_mfa\manager::REDIRECT, \tool_mfa\manager::should_require_mfa($themeurl, false)); + // Access private area. $user3 = $this->getDataGenerator()->create_user(); $privateurl = new \moodle_url("/pluginfile.php/{$user3->id}/user/private/privatefile.png"); diff --git a/public/admin/tool/policy/tests/behat/consent.feature b/public/admin/tool/policy/tests/behat/consent.feature index 25f3f261d8e..27d3b13d3b2 100644 --- a/public/admin/tool/policy/tests/behat/consent.feature +++ b/public/admin/tool/policy/tests/behat/consent.feature @@ -14,7 +14,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | passwordpolicy | 0 | | sitepolicyhandler | tool_policy | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -47,7 +47,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | P1 | This site policy | | full text1 | short text1 | draft | | P1 | This privacy policy | | full text2 | short text2 | draft | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -81,7 +81,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | P1 | This site policy | | full text2 | short text2 | active | | P1 | This site policy | | full text3 | short text3 | draft | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should see "This site policy" in the "region-main" "region" And I should see "short text2" And I should see "full text2" @@ -128,7 +128,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | This privacy policy | 1 | | full text3 | short text3 | active | loggedin | | This guests policy | 0 | | full text4 | short text4 | active | guest | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should see "This site policy" in the "region-main" "region" And I should see "short text2" And I should see "full text2" @@ -187,7 +187,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | Name | Revision | Content | Summary | Status | | This site policy | | full text2 | short text2 | active | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should see "Age and location verification" And I set the field "What is your age?" to "16" And I set the field "In which country do you live?" to "DZ" @@ -237,7 +237,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | This site policy | 0 | | full text2 | short text2 | active | all | | This privacy policy | 1 | | full text3 | short text3 | active | loggedin | And I am on homepage - And I click on "Create new account" "link" + And I click on "Sign up" "link" And I should see "This site policy" And I press "Next" And I should see "This privacy policy" @@ -457,7 +457,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | This guests policy | 0 | | full text4 | short text4 | active | guest | And I am on homepage And I change window size to "large" - When I press "Access as a guest" + When I press "Log in as guest" Then I should see "If you continue browsing this website, you agree to our policies" # Confirm when navigating, the pop-up policies are displayed. When I am on the "My courses" page @@ -489,7 +489,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | This privacy policy | 1 | | full text3 | short text3 | active | loggedin | | This guests policy | 0 | | full text4 | short text4 | active | guest | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should see "This site policy" in the "region-main" "region" And I should see "short text2" And I should see "full text2" @@ -521,7 +521,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign Then I should see "Confirm your account" And I should see "An email should have been sent to your address at user1@example.com" And I follow "Log in" - When I click on "Create new account" "link" + When I click on "Sign up" "link" # Confirm that the user can view and accept policies when attempting to create another account. Then I should see "This site policy" in the "region-main" "region" And I should see "short text2" @@ -617,10 +617,10 @@ Feature: User must accept policy managed by this plugin when logging in and sign | P1 | This site policy | | full text3 | short text3 | draft | And I am on homepage # First log in as a guest - And I press "Access as a guest" + And I press "Log in as guest" # Now sign up And I follow "Log in" - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should see "This site policy" And I should see "short text2" And I should see "full text2" @@ -668,7 +668,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | Cookies policy | We eat cookies, srsly | Here goes content. | 0 | | Terms of Service | We teach, you learn | Here goes content. | 1 | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" # The first policy with the agreement style "on its own page" must be accepted first. Then I should see "Digital maturity declaration" in the "region-main" "region" And I should see "You declare be old enough" @@ -831,7 +831,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | Cookies policy | We eat cookies, srsly | Here goes content. | 1 | loggedin | | Terms of Service | We teach, you learn | Here goes content. | 1 | guest | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" # All the policies to be displayed one by one with a button to accept each of them prior seeing the next. Then I should see "Digital maturity declaration" in the "region-main" "region" And I should see "You declare be old enough" diff --git a/public/admin/tool/policy/tests/behat/optional.feature b/public/admin/tool/policy/tests/behat/optional.feature index b56906d1754..9a0617947f3 100644 --- a/public/admin/tool/policy/tests/behat/optional.feature +++ b/public/admin/tool/policy/tests/behat/optional.feature @@ -64,7 +64,7 @@ Feature: Optional policies | OwnPageCompulsory1 | full text4 | short text4 | 1 | 0 | | OwnPageOptional1 | full text5 | short text5 | 1 | 1 | And I am on homepage - And I click on "Create new account" "link" + And I click on "Sign up" "link" # Compulsory policies displayed on own page are shown first and must be agreed. And I should see "OwnPageCompulsory1" in the "region-main" "region" And I should see "short text4" in the "region-main" "region" diff --git a/public/auth/classes/output/login.php b/public/auth/classes/output/login.php index 5b6db8b7c27..fb245885ccc 100644 --- a/public/auth/classes/output/login.php +++ b/public/auth/classes/output/login.php @@ -53,6 +53,8 @@ class login implements renderable, templatable { public $cookieshelpicon; /** @var string The error message, if any. */ public $error; + /** @var string The error title, shown as bold heading above the error message for credential failures. */ + public $errortitle; /** @var string The info message, if any. */ public $info; /** @var moodle_url Forgot password URL. */ @@ -114,7 +116,7 @@ class login implements renderable, templatable { if (is_enabled_auth('none')) { $this->instructions = get_string('loginstepsnone'); } else if ($CFG->registerauth == 'email' && empty($this->instructions)) { - $this->instructions = get_string('loginsteps', 'core', 'signup.php'); + $this->instructions = get_string('logindonthaveaccount'); } if ($CFG->maintenance_enabled == true) { @@ -142,12 +144,19 @@ class login implements renderable, templatable { } /** - * Set the error message. + * Set the error message. For the AUTH_LOGIN_FAILED case, also sets + * an errortitle so the template can render a bold heading above the detail text. * * @param string $error The error message. + * @param int $errorcode The error code from login/index.php. */ - public function set_error($error) { - $this->error = $error; + public function set_error(string $error, int $errorcode = 0): void { + if ($errorcode === AUTH_LOGIN_FAILED) { + $this->errortitle = get_string('logininvalidlogintitle'); + $this->error = get_string('logininvalidlogindetail'); + } else { + $this->error = $error; + } } /** @@ -170,10 +179,10 @@ class login implements renderable, templatable { $data->cansignup = $this->cansignup; $data->cookieshelpicon = $this->cookieshelpicon->export_for_template($output); $data->error = $this->error; + $data->errortitle = $this->errortitle; $data->info = $this->info; $data->forgotpasswordurl = $this->forgotpasswordurl->out(false); $data->hasidentityproviders = !empty($this->identityproviders); - $data->hasinstructions = !empty($this->instructions) || $this->cansignup; $data->identityproviders = $identityproviders; list($data->instructions, $data->instructionsformat) = \core_external\util::format_text($this->instructions, FORMAT_MOODLE, context_system::instance()->id); diff --git a/public/auth/email/tests/behat/signup.feature b/public/auth/email/tests/behat/signup.feature index fd72a681439..cdc07c12a17 100644 --- a/public/auth/email/tests/behat/signup.feature +++ b/public/auth/email/tests/behat/signup.feature @@ -9,7 +9,7 @@ Feature: User must accept policy when logging in and signing up | registerauth | email | | passwordpolicy | 0 | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -38,7 +38,7 @@ Feature: User must accept policy when logging in and signing up | passwordpolicy | 0 | | sitepolicy | https://moodle.org | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" Then the field "I understand and agree" matches value "0" And I set the following fields to these values: | Username | user1 | @@ -71,7 +71,7 @@ Feature: User must accept policy when logging in and signing up | username | firstname | lastname | email | | s1 | John | Doe | s1@example.com | And I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" And I set the following fields to these values: | Username | s2 | | Password | test | diff --git a/public/auth/tests/behat/displayloginfailures.feature b/public/auth/tests/behat/displayloginfailures.feature index bca58bf045d..0fa5a788156 100644 --- a/public/auth/tests/behat/displayloginfailures.feature +++ b/public/auth/tests/behat/displayloginfailures.feature @@ -18,7 +18,7 @@ Feature: Test the 'showlogfailures' feature works. And I set the field "Username" to "teacher1" And I set the field "Password" to "wrongpass" And I press "Log in" - And I should see "Invalid login, please try again" + And I should see "Unable to log in" # Now, log in with the correct credentials. When I set the field "Username" to "teacher1" And I set the field "Password" to "teacher1" @@ -38,7 +38,7 @@ Feature: Test the 'showlogfailures' feature works. And I set the field "Username" to "admin" And I set the field "Password" to "wrongpass" And I press "Log in" - And I should see "Invalid login, please try again" + And I should see "Unable to log in" # Now, log in with the correct credentials. When I set the field "Username" to "admin" And I set the field "Password" to "admin" diff --git a/public/auth/tests/behat/login.feature b/public/auth/tests/behat/login.feature index 158437ba632..b9479a40f49 100644 --- a/public/auth/tests/behat/login.feature +++ b/public/auth/tests/behat/login.feature @@ -35,7 +35,7 @@ Feature: Authentication And I set the field "Username" to "testuser" And I set the field "Password" to "unexisting" And I press "Log in" - Then I should see "Invalid login, please try again" + Then I should see "Unable to log in" Scenario: Log out using the Log out link Given I log in as "admin" diff --git a/public/auth/tests/behat/loginform.feature b/public/auth/tests/behat/loginform.feature index 4379e3e4f6f..fcc529f0de1 100644 --- a/public/auth/tests/behat/loginform.feature +++ b/public/auth/tests/behat/loginform.feature @@ -16,7 +16,7 @@ Feature: Test if the login form provides the correct feedback And I set the field "Username" to "teacher1" And I set the field "Password" to "incorrect" When I press "Log in" - Then I should see "Invalid login, please try again" + Then I should see "Unable to log in" Scenario: Test login language selector Given remote langimport tests are enabled @@ -60,7 +60,7 @@ Feature: Test if the login form provides the correct feedback Given the following config values are set as admin: | registerauth | Email-based self-registration | And I am on homepage - Then I should see "Create new account" + Then I should see "Sign up" Scenario: Set OAuth providers Given I log in as "admin" diff --git a/public/auth/tests/behat/verifyageofconsent.feature b/public/auth/tests/behat/verifyageofconsent.feature index ded4752b5be..501c8b6d165 100644 --- a/public/auth/tests/behat/verifyageofconsent.feature +++ b/public/auth/tests/behat/verifyageofconsent.feature @@ -12,7 +12,7 @@ Feature: Test the 'Digital age of consent verification' feature works. Scenario: User that is not considered a digital minor attempts to self-register on the site. # Try to access the sign up page. Given I am on homepage - And I click on "Create new account" "link" + And I click on "Sign up" "link" Then I should see "Age and location verification" When I set the field "What is your age?" to "16" And I set the field "In which country do you live?" to "DZ" @@ -21,14 +21,14 @@ Feature: Test the 'Digital age of consent verification' feature works. And I should see "Username" # Try to access the sign up page again. When I press "Cancel" - And I click on "Create new account" "link" + And I click on "Sign up" "link" Then I should see "New account" And I should see "Username" Scenario: User that is considered a digital minor attempts to self-register on the site. # Try to access the sign up page. Given I am on homepage - And I click on "Create new account" "link" + And I click on "Sign up" "link" Then I should see "Age and location verification" When I set the field "What is your age?" to "12" And I set the field "In which country do you live?" to "AT" @@ -37,6 +37,6 @@ Feature: Test the 'Digital age of consent verification' feature works. And I should see "Please ask your parent/guardian to contact:" # Try to access the sign up page again. When I click on "Back to the site home" "link" - And I click on "Create new account" "link" + And I click on "Sign up" "link" Then I should see "You are too young to create an account on this site." And I should see "Please ask your parent/guardian to contact:" diff --git a/public/enrol/self/tests/behat/self_enrolment.feature b/public/enrol/self/tests/behat/self_enrolment.feature index 09ee584699a..e7d78ada192 100644 --- a/public/enrol/self/tests/behat/self_enrolment.feature +++ b/public/enrol/self/tests/behat/self_enrolment.feature @@ -28,7 +28,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe | Custom instance name | Test student enrolment | And I log out When I am on "Course 1" course homepage - And I press "Access as a guest" + And I press "Log in as guest" Then I should see "Guests cannot access this course. Please log in." And I press "Continue" And I should see "Log in" diff --git a/public/lang/en/moodle.php b/public/lang/en/moodle.php index 0a1e027ebc4..c001dfb15e4 100644 --- a/public/lang/en/moodle.php +++ b/public/lang/en/moodle.php @@ -1233,20 +1233,40 @@ $string['loggedinasguest'] = 'You are currently using guest access'; $string['loggedinnot'] = 'You are not logged in.'; $string['login'] = 'Log in'; $string['loginactivity'] = 'Login activity'; +$string['loginagain'] = 'Log in again'; $string['loginalready'] = 'You are already logged in'; $string['loginas'] = 'Log in as'; +$string['loginasguest'] = 'Log in as guest'; $string['loginaspasswordexplain'] = '

You must enter the special "loginas password" to use this feature.
If you do not know it, ask your server administrator.

'; +$string['logindonthaveaccount'] = 'Don\'t have an account?'; +$string['loginenterpassword'] = 'Enter your password'; +$string['loginenterusernameoremail'] = 'Enter your username or email'; $string['login_failure_logs'] = 'Login failure logs'; +$string['loginforgotpassword'] = 'Forgot password?'; $string['loginguest'] = 'Access as a guest'; +$string['logininvalidlogindetail'] = 'Your login info may be incorrect. Please try again.'; +$string['logininvalidlogintitle'] = 'Unable to log in'; +$string['loginpaneltagline'] = 'You\'re part of a global learning community'; +$string['loginrequired'] = 'Login required'; +$string['loginseparatoror'] = 'OR'; $string['loginsite'] = 'Log in to the site'; +$string['loginstartsignup'] = 'Sign up'; +$string['loginstatcountries'] = 'countries'; +$string['loginstatcountries_value'] = '200+'; +$string['loginstatsites'] = 'sites'; +$string['loginstatsites_value'] = '150K'; +$string['loginstatusers'] = 'users'; +$string['loginstatusers_value'] = '500M'; $string['loginsteps'] = 'For full access to this site, you first need to create an account.'; $string['loginstepsnone'] = '

Hi!

For full access to courses you\'ll need to create yourself an account.

All you need to do is make up a username and password and use it in the form on this page!

If someone else has already chosen your username then you\'ll have to try again using a different username.

'; $string['loginto'] = 'Log in to {$a}'; -$string['loginagain'] = 'Log in again'; -$string['loginrequired'] = 'Login required'; +$string['loginwelcomeback'] = 'Welcome back'; +$string['loginwelcomedescription'] = 'Your learning journey starts here. Access courses, connect with peers, and achieve your goals.'; +$string['loginwelcometitle'] = 'Welcome to Moodle'; +$string['loginwith'] = 'Log in with'; $string['logoof'] = 'Logo of {$a}'; $string['logout'] = 'Log out'; $string['logoutconfirm'] = 'Do you really want to log out?'; diff --git a/public/login/index.php b/public/login/index.php index 3cf67bf82bc..bdbfb9b4d35 100644 --- a/public/login/index.php +++ b/public/login/index.php @@ -364,8 +364,10 @@ if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) { // We had some messages before redirect, show them now. $errormsg = $SESSION->loginerrormsg ?? ''; $infomsg = $SESSION->logininfomsg ?? ''; + $errorcode = (int) ($SESSION->loginerrorcode ?? 0); unset($SESSION->loginerrormsg); unset($SESSION->logininfomsg); + unset($SESSION->loginerrorcode); } else if ($testsession) { // No need to redirect here. @@ -376,6 +378,7 @@ if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) { // We must redirect after every password submission. if ($errormsg) { $SESSION->loginerrormsg = $errormsg; + $SESSION->loginerrorcode = $errorcode; } // Add redirect param to url. @@ -404,7 +407,7 @@ if (isloggedin() and !isguestuser()) { echo $OUTPUT->box_end(); } else { $loginform = new \core_auth\output\login($authsequence, $frm->username); - $loginform->set_error($errormsg); + $loginform->set_error($errormsg, $errorcode); $loginform->set_info($infomsg); echo $OUTPUT->render($loginform); } diff --git a/public/login/tests/behat/email_login.feature b/public/login/tests/behat/email_login.feature index 2e55b34fb0a..1bfabce5b90 100644 --- a/public/login/tests/behat/email_login.feature +++ b/public/login/tests/behat/email_login.feature @@ -21,6 +21,6 @@ Feature: Login using email address Examples: | authloginviaemail | login | message | | 0 | testuser | You are logged in as | - | 0 | user@example.com | Invalid login, please try again | + | 0 | user@example.com | Unable to log in | | 1 | testuser | You are logged in as | | 1 | user@example.com | You are logged in as | diff --git a/public/mod/forum/tests/behat/guest_users.feature b/public/mod/forum/tests/behat/guest_users.feature index f19be705fba..22c361663d1 100644 --- a/public/mod/forum/tests/behat/guest_users.feature +++ b/public/mod/forum/tests/behat/guest_users.feature @@ -29,7 +29,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | teacher | forum | Forum discussion 1 | How awesome is this forum discussion? | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as 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" @@ -48,7 +48,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | forum | Forum (single discussion) | C1 | forum | single | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as 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)" @@ -63,7 +63,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | teacher | forum | Forum discussion 1 | How awesome is this forum discussion? | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as 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" @@ -80,7 +80,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | teacher | forum | Forum discussion 1 | How awesome is this forum discussion? | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as 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" @@ -108,7 +108,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | forum | Forum (single discussion) | C1 | forum | single | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as guest" And I am on the "Forum (single discussion)" "forum activity" page And I should see "Forum (single discussion)" Then I should see "Reply" @@ -131,7 +131,7 @@ Feature: Guest and not logged users could see the option to add new post or repl | teacher | forum | Forum discussion 1 | How awesome is this forum discussion? | And I log out And I am on "Course 1" course homepage - When I press "Access as a guest" + When I press "Log in as 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" diff --git a/public/theme/boost/classes/output/core_renderer.php b/public/theme/boost/classes/output/core_renderer.php index 62ef886d9fb..d26e093ac0b 100644 --- a/public/theme/boost/classes/output/core_renderer.php +++ b/public/theme/boost/classes/output/core_renderer.php @@ -16,6 +16,7 @@ namespace theme_boost\output; +use context_course; use moodle_url; use html_writer; use get_string; @@ -252,4 +253,29 @@ class core_renderer extends \core_renderer { } return $firstview; } + + /** + * Renders the Boost login form context. + * + * @param \core_auth\output\login $form The renderable. + * @return string + */ + public function render_login(\core_auth\output\login $form) { + global $CFG, $SITE; + + $context = $form->export_for_template($this); + $url = $this->get_logo_url(); + if ($url) { + $url = $url->out(false); + } + $context->logourl = $url; + $context->sitename = format_string( + $SITE->fullname, + true, + ['context' => context_course::instance(SITEID), 'escape' => false] + ); + $context->hasauthinstructions = !empty($CFG->auth_instructions); + + return $this->render_from_template('core/loginform', $context); + } } diff --git a/public/theme/boost/layout/login.php b/public/theme/boost/layout/login.php index e86169dfc06..1a2a0c24d7c 100644 --- a/public/theme/boost/layout/login.php +++ b/public/theme/boost/layout/login.php @@ -26,11 +26,17 @@ defined('MOODLE_INTERNAL') || die(); $bodyattributes = $OUTPUT->body_attributes(); +// Left-panel instructions. +$leftinstructions = get_string('loginwelcomedescription'); +if (!empty($CFG->auth_instructions)) { + $leftinstructions = $CFG->auth_instructions; +} + $templatecontext = [ 'sitename' => format_string($SITE->shortname, true, ['context' => context_course::instance(SITEID), "escape" => false]), 'output' => $OUTPUT, - 'bodyattributes' => $bodyattributes + 'bodyattributes' => $bodyattributes, + 'leftinstructions' => $leftinstructions, ]; echo $OUTPUT->render_from_template('theme_boost/login', $templatecontext); - diff --git a/public/theme/boost/lib.php b/public/theme/boost/lib.php index 3207cfe683c..df664c7d167 100644 --- a/public/theme/boost/lib.php +++ b/public/theme/boost/lib.php @@ -58,8 +58,9 @@ function theme_boost_get_extra_scss($theme) { // Sets the login background image. $loginbackgroundimageurl = $theme->setting_file_url('loginbackgroundimage', 'loginbackgroundimage'); if (!empty($loginbackgroundimageurl)) { - $content .= 'body.pagelayout-login #page { '; - $content .= "background-image: url('$loginbackgroundimageurl'); background-size: cover;"; + $content .= 'body.pagelayout-login #page .login-layout-left { '; + $content .= "background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), " . + "url('$loginbackgroundimageurl'); background-size: cover;"; $content .= ' }'; } diff --git a/public/theme/boost/scss/moodle/login.scss b/public/theme/boost/scss/moodle/login.scss index 3d10cf0b8cf..364b1524442 100644 --- a/public/theme/boost/scss/moodle/login.scss +++ b/public/theme/boost/scss/moodle/login.scss @@ -1,84 +1,164 @@ -$loginbackground-gradient-from: $gray-100 !default; -$loginbackground-gradient-to: $gray-300 !default; -$logincontainer-bg: $white !default; -$logincontainer-padding: 3rem !default; -$logincontainer-shadow: $box-shadow !default; -$logindivider-margin-top: 1.5rem !default; -$logindivider-margin-bottom: 1.5rem !default; -$logindivider-border: $border-color !default; -$login-identity-provider-btn-border: $border-color !default; +$login-layout-left-bg: $primary !default; +$login-layout-panel-padding: 3rem !default; +$login-layout-content-width: 576px !default; +$login-layout-copy-width: 360px !default; +$login-input-bg: $gray-100 !default; -.pagelayout-login #region-main { - border: 0; - background-color: inherit; -} +.pagelayout-login { + #region-main, + #region-main-box { + border: 0; + background-color: transparent; + } -.pagelayout-login #page { - background: $loginbackground-gradient-from; - @include gradient-x($loginbackground-gradient-from, $loginbackground-gradient-to, 0%, 100%); - div[role="main"] { - height: 100%; + #page { + margin: 0; + min-height: 100vh; + background-color: $white; } } -.login-wrapper { +.login-layout-left { + background-color: $login-layout-left-bg; + color: color-contrast($login-layout-left-bg); + position: sticky; + top: 0; + align-self: flex-start; + height: 100vh; display: flex; align-items: center; justify-content: center; - height: 100%; + padding: $login-layout-panel-padding; +} + +.login-layout-left-content { + max-width: $login-layout-copy-width; + text-align: center; +} + +.login-layout-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + justify-items: center; +} + +.login-layout-stat { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.login-layout-stat-value { + font-size: $h5-font-size; + line-height: 1; +} + +.login-layout-right { + min-height: 100vh; + padding: $login-layout-panel-padding; + display: flex; + justify-content: center; +} + +.login-layout-right-content { + width: 100%; + max-width: $login-layout-content-width; + margin: auto 0; } .login-container { - background-color: $logincontainer-bg; - padding: $logincontainer-padding; - box-shadow: $logincontainer-shadow; - margin-bottom: 2rem; - @include border-radius(); - .login-languagemenu { + .login-form { + .form-control { + background-color: $login-input-bg; + box-shadow: none; + + &:hover { + background-color: $login-input-bg; + } + + &:focus { + background-color: $login-input-bg; + border-color: $input-focus-border-color; + box-shadow: $input-focus-box-shadow; + } + } + + .toggle-sensitive-wrapper .toggle-sensitive-btn { + --bs-btn-bg: #{$login-input-bg}; + --bs-btn-border-color: #{$input-border-color}; + --bs-btn-hover-bg: #{$login-input-bg}; + --bs-btn-hover-border-color: #{$input-border-color}; + --bs-btn-active-bg: #{$login-input-bg}; + --bs-btn-active-border-color: #{$input-border-color}; + border-inline-start: none; + color: $gray-700; + + &:focus, + &:focus-visible { + background-color: $login-input-bg; + border-color: $input-focus-border-color; + box-shadow: $input-focus-box-shadow; + } + } + } + + .login-separator { display: flex; - justify-content: flex-start; + align-items: center; + gap: 0.75rem; + color: $gray-600; + font-size: $font-size-sm; + text-transform: uppercase; + letter-spacing: 0.08em; + + &::before, + &::after { + content: ""; + flex: 1; + border-top: $border-width solid $border-color; + } + } + + .login-identityprovider-btn { + width: 100%; + background-color: $white; + border-color: $gray-400; + color: $gray-600; + + &:hover, + &:focus { + background-color: $gray-100; + border-color: $gray-500; + } + } + + .login-cookiesnotice { + .btn-link { + font-size: $font-size-sm; + color: $gray-600; + + &:hover, + &:focus { + color: $gray-700; + } + } + } + + .login-languagemenu { .dropdown-menu { max-height: 300px; overflow-y: auto; } } - .login-logo { - display: flex; - justify-content: center; - margin-bottom: 1rem; - } - .login-divider { - margin-top: $logindivider-margin-top; - margin-bottom: $logindivider-margin-bottom; - border-top: $border-width solid $logindivider-border; - } - - h1.login-heading { - font-size: $h2-font-size; - } - - h2.login-heading { - font-size: $h4-font-size; - } - .login-identityproviders { - .login-identityprovider-btn { - border: $border-width solid $login-identity-provider-btn-border; - } - } - .divider { - width: $border-width; - background-color: $gray-300; - height: $font-size-base * 2; - } - .action-menu-trigger { - a { - margin: 0.5rem 0; - } - } } -@include media-breakpoint-up(md) { - .login-container { - width: 500px !important; /* stylelint-disable-line declaration-no-important */ +@include media-breakpoint-down(lg) { + .login-layout-right { + padding: 1.5rem 1rem; + } + + .login-layout-right-content { + max-width: 100%; + margin: 0; } } diff --git a/public/theme/boost/style/moodle.css b/public/theme/boost/style/moodle.css index 9bbdb9edb9b..ceb9e1ed194 100644 --- a/public/theme/boost/style/moodle.css +++ b/public/theme/boost/style/moodle.css @@ -35550,72 +35550,135 @@ textarea[data-auto-rows] { opacity: 1; } -.pagelayout-login #region-main { +.pagelayout-login #region-main, +.pagelayout-login #region-main-box { border: 0; - background-color: inherit; + background-color: transparent; } - .pagelayout-login #page { - background: #f8f9fa; - background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%); -} -.pagelayout-login #page div[role=main] { - height: 100%; + margin: 0; + min-height: 100vh; + background-color: #ffffff; } -.login-wrapper { +.login-layout-left { + background-color: #0f6cbf; + color: #ffffff; + position: sticky; + top: 0; + align-self: flex-start; + height: 100vh; display: flex; align-items: center; justify-content: center; - height: 100%; + padding: 3rem; } -.login-container { - background-color: #ffffff; - padding: 3rem; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); - margin-bottom: 2rem; - border-radius: 0.5rem; +.login-layout-left-content { + max-width: 360px; + text-align: center; } -.login-container .login-languagemenu { + +.login-layout-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + justify-items: center; +} + +.login-layout-stat { display: flex; - justify-content: flex-start; + flex-direction: column; + gap: 0.25rem; +} + +.login-layout-stat-value { + font-size: 1.25rem; + line-height: 1; +} + +.login-layout-right { + min-height: 100vh; + padding: 3rem; + display: flex; + justify-content: center; +} + +.login-layout-right-content { + width: 100%; + max-width: 576px; + margin: auto 0; +} + +.login-container .login-form .form-control { + background-color: #f8f9fa; + box-shadow: none; +} +.login-container .login-form .form-control:hover { + background-color: #f8f9fa; +} +.login-container .login-form .form-control:focus { + background-color: #f8f9fa; + border-color: #87b6df; + box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75); +} +.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn { + --bs-btn-bg: #f8f9fa; + --bs-btn-border-color: var(--bs-gray-500); + --bs-btn-hover-bg: #f8f9fa; + --bs-btn-hover-border-color: var(--bs-gray-500); + --bs-btn-active-bg: #f8f9fa; + --bs-btn-active-border-color: var(--bs-gray-500); + border-inline-start: none; + color: #495057; +} +.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus, .login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus-visible { + background-color: #f8f9fa; + border-color: #87b6df; + box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75); +} +.login-container .login-separator { + display: flex; + align-items: center; + gap: 0.75rem; + color: #6a737b; + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.08em; +} +.login-container .login-separator::before, .login-container .login-separator::after { + content: ""; + flex: 1; + border-top: 1px solid #dee2e6; +} +.login-container .login-identityprovider-btn { + width: 100%; + background-color: #ffffff; + border-color: #ced4da; + color: #6a737b; +} +.login-container .login-identityprovider-btn:hover, .login-container .login-identityprovider-btn:focus { + background-color: #f8f9fa; + border-color: #8f959e; +} +.login-container .login-cookiesnotice .btn-link { + font-size: 0.875rem; + color: #6a737b; +} +.login-container .login-cookiesnotice .btn-link:hover, .login-container .login-cookiesnotice .btn-link:focus { + color: #495057; } .login-container .login-languagemenu .dropdown-menu { max-height: 300px; overflow-y: auto; } -.login-container .login-logo { - display: flex; - justify-content: center; - margin-bottom: 1rem; -} -.login-container .login-divider { - margin-top: 1.5rem; - margin-bottom: 1.5rem; - border-top: 1px solid #dee2e6; -} -.login-container h1.login-heading, .login-container .login-heading.h1 { - font-size: 2rem; -} -.login-container h2.login-heading, .login-container .login-heading.h2 { - font-size: 1.5rem; -} -.login-container .login-identityproviders .login-identityprovider-btn { - border: 1px solid #dee2e6; -} -.login-container .divider { - width: 1px; - background-color: #dee2e6; - height: 2rem; -} -.login-container .action-menu-trigger a { - margin: 0.5rem 0; -} -@media (min-width: 768px) { - .login-container { - width: 500px !important; /* stylelint-disable-line declaration-no-important */ +@media (max-width: 991.98px) { + .login-layout-right { + padding: 1.5rem 1rem; + } + .login-layout-right-content { + max-width: 100%; + margin: 0; } } /* modules.less */ diff --git a/public/theme/boost/templates/core/login_layout.mustache b/public/theme/boost/templates/core/login_layout.mustache new file mode 100644 index 00000000000..92c1098ab6c --- /dev/null +++ b/public/theme/boost/templates/core/login_layout.mustache @@ -0,0 +1,48 @@ +{{! + 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 . +}} +{{! + @template core/login_layout + + Split-screen layout for login-flow pages (login, MFA, etc.). + + Provides a two-column structure: a decorative left panel (hidden on mobile) + and a right panel that receives the page's main content. The left panel + content is loaded from the core/login_panel partial, which themes can + override to customise the welcome copy and branding. + + Context variables required for this template: + * output - The core renderer output object (provides main_content). + + Example context (json): + { + "output": { + "main_content": "

Login form goes here

" + } + } +}} +
+ + +
diff --git a/public/theme/boost/templates/core/login_panel.mustache b/public/theme/boost/templates/core/login_panel.mustache new file mode 100644 index 00000000000..294ad49b268 --- /dev/null +++ b/public/theme/boost/templates/core/login_panel.mustache @@ -0,0 +1,49 @@ +{{! + 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 . +}} +{{! + @template core/login_panel + + Default content for the left panel of the split-screen login layout. + + Example context (json): + { + "leftinstructions": "

Your learning journey starts here. Access courses, connect with peers, and achieve your goals.

" + } +}} + diff --git a/public/theme/boost/templates/core/loginform.mustache b/public/theme/boost/templates/core/loginform.mustache new file mode 100644 index 00000000000..e91d517317d --- /dev/null +++ b/public/theme/boost/templates/core/loginform.mustache @@ -0,0 +1,253 @@ +{{! + 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 . +}} +{{! + @template core/loginform + + Moodle template for the login page. + + Context variables required for this template: + * autofocusform: Auto focus on form ?, + * canloginasguest - Is guest login allowed?, + * canloginbyemail - Is login by email allowed?, + * cansignup - Signup allowed?, + * showloginform - Hide the standard login form if it not necessary (only OAuth2 for example) + * error - Any errors in the form?, + * errortitle - Optional bold heading shown above the error message (credential failures only), + * hasauthinstructions - Flag, set to true when auth_instructions is configured, + * info - Info notification to display, + * forgotpasswordurl - Forgot password url, + * hasidentityproviders - Flag, set to true to hide identity providers, + * identityproviders - List of identity providers, + * instructions - Instructions, + * loginurl - Login url, + * signupurl - Signup url, + * logourl - Flag, logo url, + * sitename - Name of site., + * logintoken - Random token to protect login request., + * maintenance - Maintenance message + + Example context (json): + { + "autofocusform": false, + "canloginasguest": "1", + "canloginbyemail": false, + "cansignup": true, + "showloginform": true, + "error": "", + "errortitle": "", + "hasauthinstructions": false, + "info": "", + "forgotpasswordurl": "http://localhost/stable_master/login/forgot_password.php", + "hasidentityproviders": false, + "identityproviders": [], + "instructions": "For full access to this site, you first need to create an account.", + "loginurl": "http://localhost/stable_master/login/index.php", + "signupurl": "http://localhost/stable_master/login/signup.php", + "logourl": false, + "sitename": "Beer & Chips", + "logintoken": "randomstring", + "maintenance": "For full access to this site, you need to login in as an admin.", + "languagemenu": "Choose language", + "togglepassword": true, + "smallscreensonly": true + } +}} + +
+ {{#logourl}} + + {{/logourl}} +

{{#str}}loginwelcomeback{{/str}}

+

{{#str}} loginto, core, {{sitename}} {{/str}}

+ {{#maintenance}} + + {{/maintenance}} + {{#error}} + + {{/error}} + {{#info}} +
{{info}}
+ {{/info}} + {{#showloginform}} + + {{/showloginform}} + {{#hasauthinstructions}} +
+ {{{instructions}}} +
+ {{/hasauthinstructions}} + {{^hasauthinstructions}} + {{#cansignup}} +
+ {{#instructions}} + {{{instructions}}} + {{/instructions}} + {{#str}}loginstartsignup{{/str}} +
+ {{/cansignup}} + {{^cansignup}} + {{#instructions}} +

{{{instructions}}}

+ {{/instructions}} + {{/cansignup}} + {{/hasauthinstructions}} + {{#hasauthinstructions}} + {{#cansignup}} + + {{/cansignup}} + {{/hasauthinstructions}} + {{#hasidentityproviders}} + + {{/hasidentityproviders}} + {{^hasidentityproviders}} + {{#canloginasguest}} + + {{/canloginasguest}} + {{/hasidentityproviders}} + {{#hasidentityproviders}} + + {{/hasidentityproviders}} + {{#canloginasguest}} +
+ + + + +
+ {{/canloginasguest}} + {{#languagemenu}} + + {{/languagemenu}} + +
+ +{{#js}} + {{^error}} + {{#autofocusform}} + require(['core_form/events'], function(FormEvent) { + function autoFocus() { + const userNameField = document.getElementById('username'); + const passwordField = document.getElementById('password'); + if (userNameField && userNameField.value.length == 0) { + userNameField.focus(); + } else if (passwordField) { + passwordField.focus(); + } + } + autoFocus(); + window.addEventListener(FormEvent.eventTypes.fieldStructureChanged, autoFocus); + }); + {{/autofocusform}} + {{/error}} + require(['core/pending'], function(Pending) { + const errorMessageDiv = document.getElementById('loginerrormessage'); + const infoMessageDiv = document.getElementById('logininfomessage'); + const errorMessage = errorMessageDiv?.textContent.trim(); + const infoMessage = infoMessageDiv?.textContent.trim(); + if (errorMessage || infoMessage) { + const pendingJS = new Pending('login-move-focus'); + const usernameField = document.getElementById('username'); + setTimeout(function() { + if (errorMessage && usernameField) { + usernameField.focus(); + } + if (errorMessage) { + errorMessageDiv.innerHTML += " "; + } + if (infoMessage) { + infoMessageDiv.innerHTML += " "; + } + pendingJS.resolve(); + }, 500); + } + }); + {{#togglepassword}} + require(['core/togglesensitive'], function(ToggleSensitive) { + ToggleSensitive.init("password", {{smallscreensonly}}); + }); + {{/togglepassword}} + require(['core_form/submit'], function(Submit) { + Submit.init("loginbtn"); + {{#canloginasguest}} + Submit.init("loginguestbtn"); + {{/canloginasguest}} + }); +{{/js}} diff --git a/public/theme/boost/templates/login.mustache b/public/theme/boost/templates/login.mustache index 9014343f524..176dc57651e 100644 --- a/public/theme/boost/templates/login.mustache +++ b/public/theme/boost/templates/login.mustache @@ -38,18 +38,8 @@ {{{ output.standard_top_of_body_html }}} -
-
-
-
- -
-
-
+
+ {{> core/login_layout }}
{{> theme_boost/footer }}
diff --git a/public/theme/classic/lib.php b/public/theme/classic/lib.php index 2711283effa..c98d606d7be 100644 --- a/public/theme/classic/lib.php +++ b/public/theme/classic/lib.php @@ -109,8 +109,9 @@ function theme_classic_get_extra_scss($theme) { // Sets the login background image. $loginbackgroundimageurl = $theme->setting_file_url('loginbackgroundimage', 'loginbackgroundimage'); if (!empty($loginbackgroundimageurl)) { - $content .= 'body.pagelayout-login #page { '; - $content .= "background-image: url('$loginbackgroundimageurl'); background-size: cover;"; + $content .= 'body.pagelayout-login #page .login-layout-left { '; + $content .= "background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), " . + "url('$loginbackgroundimageurl'); background-size: cover;"; $content .= ' }'; } diff --git a/public/theme/classic/style/moodle.css b/public/theme/classic/style/moodle.css index d6c3a7d3257..50bc9fe9750 100644 --- a/public/theme/classic/style/moodle.css +++ b/public/theme/classic/style/moodle.css @@ -35550,72 +35550,135 @@ textarea[data-auto-rows] { opacity: 1; } -.pagelayout-login #region-main { +.pagelayout-login #region-main, +.pagelayout-login #region-main-box { border: 0; - background-color: inherit; + background-color: transparent; } - .pagelayout-login #page { - background: #f8f9fa; - background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%); -} -.pagelayout-login #page div[role=main] { - height: 100%; + margin: 0; + min-height: 100vh; + background-color: #fff; } -.login-wrapper { +.login-layout-left { + background-color: #0f6cbf; + color: #fff; + position: sticky; + top: 0; + align-self: flex-start; + height: 100vh; display: flex; align-items: center; justify-content: center; - height: 100%; + padding: 3rem; } -.login-container { - background-color: #fff; - padding: 3rem; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); - margin-bottom: 2rem; - border-radius: 0.375rem; +.login-layout-left-content { + max-width: 360px; + text-align: center; } -.login-container .login-languagemenu { + +.login-layout-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + justify-items: center; +} + +.login-layout-stat { display: flex; - justify-content: flex-start; + flex-direction: column; + gap: 0.25rem; +} + +.login-layout-stat-value { + font-size: 1.25rem; + line-height: 1; +} + +.login-layout-right { + min-height: 100vh; + padding: 3rem; + display: flex; + justify-content: center; +} + +.login-layout-right-content { + width: 100%; + max-width: 576px; + margin: auto 0; +} + +.login-container .login-form .form-control { + background-color: #f8f9fa; + box-shadow: none; +} +.login-container .login-form .form-control:hover { + background-color: #f8f9fa; +} +.login-container .login-form .form-control:focus { + background-color: #f8f9fa; + border-color: #87b6df; + box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75); +} +.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn { + --bs-btn-bg: #f8f9fa; + --bs-btn-border-color: #8f959e; + --bs-btn-hover-bg: #f8f9fa; + --bs-btn-hover-border-color: #8f959e; + --bs-btn-active-bg: #f8f9fa; + --bs-btn-active-border-color: #8f959e; + border-inline-start: none; + color: #495057; +} +.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus, .login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus-visible { + background-color: #f8f9fa; + border-color: #87b6df; + box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75); +} +.login-container .login-separator { + display: flex; + align-items: center; + gap: 0.75rem; + color: #6a737b; + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.08em; +} +.login-container .login-separator::before, .login-container .login-separator::after { + content: ""; + flex: 1; + border-top: 1px solid #dee2e6; +} +.login-container .login-identityprovider-btn { + width: 100%; + background-color: #fff; + border-color: #ced4da; + color: #6a737b; +} +.login-container .login-identityprovider-btn:hover, .login-container .login-identityprovider-btn:focus { + background-color: #f8f9fa; + border-color: #8f959e; +} +.login-container .login-cookiesnotice .btn-link { + font-size: 0.875rem; + color: #6a737b; +} +.login-container .login-cookiesnotice .btn-link:hover, .login-container .login-cookiesnotice .btn-link:focus { + color: #495057; } .login-container .login-languagemenu .dropdown-menu { max-height: 300px; overflow-y: auto; } -.login-container .login-logo { - display: flex; - justify-content: center; - margin-bottom: 1rem; -} -.login-container .login-divider { - margin-top: 1.5rem; - margin-bottom: 1.5rem; - border-top: 1px solid #dee2e6; -} -.login-container h1.login-heading, .login-container .login-heading.h1 { - font-size: 2rem; -} -.login-container h2.login-heading, .login-container .login-heading.h2 { - font-size: 1.5rem; -} -.login-container .login-identityproviders .login-identityprovider-btn { - border: 1px solid #dee2e6; -} -.login-container .divider { - width: 1px; - background-color: #dee2e6; - height: 2rem; -} -.login-container .action-menu-trigger a { - margin: 0.5rem 0; -} -@media (min-width: 768px) { - .login-container { - width: 500px !important; /* stylelint-disable-line declaration-no-important */ +@media (max-width: 991.98px) { + .login-layout-right { + padding: 1.5rem 1rem; + } + .login-layout-right-content { + max-width: 100%; + margin: 0; } } /* modules.less */ diff --git a/public/user/tests/behat/custom_profile_fields.feature b/public/user/tests/behat/custom_profile_fields.feature index 440d8eb77fe..c2576c20790 100644 --- a/public/user/tests/behat/custom_profile_fields.feature +++ b/public/user/tests/behat/custom_profile_fields.feature @@ -32,7 +32,7 @@ Feature: Custom profile fields should be visible and editable by those with the @javascript Scenario: Visible custom profile fields can be part of the sign up form for anonymous users. Given I am on homepage - When I click on "Create new account" "link" + When I click on "Sign up" "link" And I expand all fieldsets Then I should not see "notvisible_field" And I should see "uservisible_field" @@ -44,7 +44,7 @@ Feature: Custom profile fields should be visible and editable by those with the Given I log in as "guest" And I am on site homepage And I follow "Log in" - When I click on "Create new account" "link" + When I click on "Sign up" "link" And I expand all fieldsets Then I should not see "notvisible_field" And I should see "uservisible_field" diff --git a/public/user/tests/behat/name_fields.feature b/public/user/tests/behat/name_fields.feature index 511335e2fd7..0962c957233 100644 --- a/public/user/tests/behat/name_fields.feature +++ b/public/user/tests/behat/name_fields.feature @@ -10,7 +10,7 @@ Feature: Both first name and last name are always available for every user | registerauth | email | | passwordpolicy | 0 | And I am on homepage - And I click on "Create new account" "link" + And I click on "Sign up" "link" When I set the following fields to these values: | Username | mrwhitespace | | Password | Gue$$m3ifY0uC&n |