From 357fda719a590679331015dbfb4b269e7ddcd1f9 Mon Sep 17 00:00:00 2001 From: Albert Gasset Date: Mon, 5 Aug 2024 15:36:00 +0200 Subject: [PATCH] MOBILE-4631 login: Hide the login form in the app when is hidden in LMS --- .../classes/sites/unauthenticated-site.ts | 1 + .../login-methods/login-methods.html | 3 +- .../components/login-methods/login-methods.ts | 1 + src/core/features/login/constants.ts | 2 + .../login/pages/credentials/credentials.html | 5 +- .../login/pages/credentials/credentials.ts | 17 ++++- .../login/pages/reconnect/reconnect.html | 5 +- .../login/pages/reconnect/reconnect.ts | 13 +++- .../features/login/services/login-helper.ts | 18 ++++++ .../tests/behat/showloginform_setting.feature | 60 ++++++++++++++++++ ...wloginform-setting-in-the-app-login_10.png | Bin 0 -> 20542 bytes ...inform-setting-in-the-app-reconnect_10.png | Bin 0 -> 18200 bytes src/core/features/settings/pages/dev/dev.html | 5 ++ src/core/features/settings/pages/dev/dev.ts | 19 +++++- 14 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 src/core/features/login/tests/behat/showloginform_setting.feature create mode 100644 src/core/features/login/tests/behat/snapshots/test-showloginform-setting-in-the-app-login_10.png create mode 100644 src/core/features/login/tests/behat/snapshots/test-showloginform-setting-in-the-app-reconnect_10.png diff --git a/src/core/classes/sites/unauthenticated-site.ts b/src/core/classes/sites/unauthenticated-site.ts index 68ef3f975..3d4a5e3fa 100644 --- a/src/core/classes/sites/unauthenticated-site.ts +++ b/src/core/classes/sites/unauthenticated-site.ts @@ -464,6 +464,7 @@ export type CoreSitePublicConfigResponse = { tool_mobile_setuplink?: string; // App download page. tool_mobile_qrcodetype?: CoreSiteQRCodeType; // eslint-disable-line @typescript-eslint/naming-convention warnings?: CoreWSExternalWarning[]; + showloginform?: number; // @since 4.5. Display default login form. }; /** diff --git a/src/core/features/login/components/login-methods/login-methods.html b/src/core/features/login/components/login-methods/login-methods.html index 9a405ae15..be93e7972 100644 --- a/src/core/features/login/components/login-methods/login-methods.html +++ b/src/core/features/login/components/login-methods/login-methods.html @@ -1,4 +1,5 @@ -
+ diff --git a/src/core/features/login/components/login-methods/login-methods.ts b/src/core/features/login/components/login-methods/login-methods.ts index 88ac5a23e..f4c24f255 100644 --- a/src/core/features/login/components/login-methods/login-methods.ts +++ b/src/core/features/login/components/login-methods/login-methods.ts @@ -32,6 +32,7 @@ export class CoreLoginMethodsComponent implements OnInit { @Input() siteUrl = ''; @Input() siteConfig?: CoreSitePublicConfigResponse; @Input() redirectData?: CoreRedirectPayload; + @Input() showLoginForm = true; isBrowserSSO = false; showScanQR = false; diff --git a/src/core/features/login/constants.ts b/src/core/features/login/constants.ts index b83fbe9d6..2cb7ac285 100644 --- a/src/core/features/login/constants.ts +++ b/src/core/features/login/constants.ts @@ -21,6 +21,8 @@ export const EMAIL_SIGNUP_FEATURE_NAME = 'CoreLoginEmailSignup'; export const FORGOTTEN_PASSWORD_FEATURE_NAME = 'NoDelegate_ForgottenPassword'; export const IDENTITY_PROVIDERS_FEATURE_NAME = 'NoDelegate_IdentityProviders'; export const IDENTITY_PROVIDER_FEATURE_NAME_PREFIX = 'NoDelegate_IdentityProvider_'; +export const ALWAYS_SHOW_LOGIN_FORM = 'always_show_login_form'; +export const ALWAYS_SHOW_LOGIN_FORM_CHANGED = 'always_show_login_form_changed'; // Event indicating that a user left the app because it wasn't supported by a site. export const APP_UNSUPPORTED_CHURN = 'app_unsupported_churn'; diff --git a/src/core/features/login/pages/credentials/credentials.html b/src/core/features/login/pages/credentials/credentials.html index caacc02d9..c6d71047b 100644 --- a/src/core/features/login/pages/credentials/credentials.html +++ b/src/core/features/login/pages/credentials/credentials.html @@ -43,7 +43,8 @@
-
diff --git a/src/core/features/login/pages/credentials/credentials.ts b/src/core/features/login/pages/credentials/credentials.ts index aad90fa57..8c8ccaa14 100644 --- a/src/core/features/login/pages/credentials/credentials.ts +++ b/src/core/features/login/pages/credentials/credentials.ts @@ -24,7 +24,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreLoginHelper } from '@features/login/services/login-helper'; import { Translate } from '@singletons'; import { CoreSitePublicConfigResponse, CoreUnauthenticatedSite } from '@classes/sites/unauthenticated-site'; -import { CoreEvents } from '@singletons/events'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreNavigator } from '@services/navigator'; import { CoreForms } from '@singletons/form'; import { CoreUserSupport } from '@features/user/services/support'; @@ -33,7 +33,11 @@ import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest import { SafeHtml } from '@angular/platform-browser'; import { CorePlatform } from '@services/platform'; import { CoreSitesFactory } from '@services/sites-factory'; -import { EMAIL_SIGNUP_FEATURE_NAME, FORGOTTEN_PASSWORD_FEATURE_NAME } from '@features/login/constants'; +import { + ALWAYS_SHOW_LOGIN_FORM_CHANGED, + EMAIL_SIGNUP_FEATURE_NAME, + FORGOTTEN_PASSWORD_FEATURE_NAME, +} from '@features/login/constants'; import { CoreCustomURLSchemes } from '@services/urlschemes'; import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreKeyboard } from '@singletons/keyboard'; @@ -66,6 +70,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { siteConfig?: CoreSitePublicConfigResponse; siteCheckError = ''; displaySiteUrl = false; + showLoginForm = true; protected siteCheck?: CoreSiteCheckResponse; protected eventThrown = false; @@ -73,6 +78,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { protected siteId?: string; protected urlToOpen?: string; protected valueChangeSubscription?: Subscription; + protected alwaysShowLoginFormObserver?: CoreEventObserver; constructor( protected fb: FormBuilder, @@ -137,6 +143,10 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { } }); } + + this.alwaysShowLoginFormObserver = CoreEvents.on(ALWAYS_SHOW_LOGIN_FORM_CHANGED, async () => { + this.showLoginForm = await CoreLoginHelper.shouldShowLoginForm(this.siteConfig); + }); } /** @@ -191,6 +201,8 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { * Treat the site configuration (if it exists). */ protected async treatSiteConfig(): Promise { + this.showLoginForm = await CoreLoginHelper.shouldShowLoginForm(this.siteConfig); + if (!this.siteConfig) { this.authInstructions = undefined; this.canSignup = false; @@ -365,6 +377,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { this.siteId, ); this.valueChangeSubscription?.unsubscribe(); + this.alwaysShowLoginFormObserver?.off(); } } diff --git a/src/core/features/login/pages/reconnect/reconnect.html b/src/core/features/login/pages/reconnect/reconnect.html index 3c529966e..2a5c92b3a 100644 --- a/src/core/features/login/pages/reconnect/reconnect.html +++ b/src/core/features/login/pages/reconnect/reconnect.html @@ -59,7 +59,8 @@
- + + [redirectData]="redirectData" [showLoginForm]="showLoginForm" />
diff --git a/src/core/features/login/pages/reconnect/reconnect.ts b/src/core/features/login/pages/reconnect/reconnect.ts index 642831241..181ef2f13 100644 --- a/src/core/features/login/pages/reconnect/reconnect.ts +++ b/src/core/features/login/pages/reconnect/reconnect.ts @@ -21,7 +21,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CoreLoginHelper } from '@features/login/services/login-helper'; import { CoreSite } from '@classes/sites/site'; -import { CoreEvents } from '@singletons/events'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreError } from '@classes/errors/error'; import { CoreNavigator, CoreRedirectPayload } from '@services/navigator'; import { CoreForms } from '@singletons/form'; @@ -31,7 +31,7 @@ import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/suppo import { Translate } from '@singletons'; import { SafeHtml } from '@angular/platform-browser'; import { CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site'; -import { FORGOTTEN_PASSWORD_FEATURE_NAME } from '@features/login/constants'; +import { ALWAYS_SHOW_LOGIN_FORM_CHANGED, FORGOTTEN_PASSWORD_FEATURE_NAME } from '@features/login/constants'; import { CoreKeyboard } from '@singletons/keyboard'; /** @@ -63,11 +63,13 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { exceededAttemptsHTML?: SafeHtml | string | null; siteConfig?: CoreSitePublicConfigResponse; redirectData?: CoreRedirectPayload; + showLoginForm = true; protected viewLeft = false; protected eventThrown = false; protected loginSuccessful = false; protected username = ''; + protected alwaysShowLoginFormObserver?: CoreEventObserver; constructor( protected fb: FormBuilder, @@ -126,6 +128,10 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { await this.checkSiteConfig(); + this.alwaysShowLoginFormObserver = CoreEvents.on(ALWAYS_SHOW_LOGIN_FORM_CHANGED, async () => { + this.showLoginForm = await CoreLoginHelper.shouldShowLoginForm(this.siteConfig); + }); + this.showLoading = false; } catch (error) { CoreDomUtils.showErrorModal(error); @@ -147,6 +153,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { }, this.siteId, ); + this.alwaysShowLoginFormObserver?.off(); } /** @@ -168,6 +175,8 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { readingStrategy: CoreSitesReadingStrategy.PREFER_NETWORK, })); + this.showLoginForm = await CoreLoginHelper.shouldShowLoginForm(this.siteConfig); + if (!this.siteConfig) { return; } diff --git a/src/core/features/login/services/login-helper.ts b/src/core/features/login/services/login-helper.ts index 856d729ca..8a92e8108 100644 --- a/src/core/features/login/services/login-helper.ts +++ b/src/core/features/login/services/login-helper.ts @@ -47,6 +47,8 @@ import { TypeOfLogin, } from '@classes/sites/unauthenticated-site'; import { + ALWAYS_SHOW_LOGIN_FORM, + ALWAYS_SHOW_LOGIN_FORM_CHANGED, APP_UNSUPPORTED_CHURN, EMAIL_SIGNUP_FEATURE_NAME, FAQ_QRCODE_IMAGE_HTML, @@ -924,6 +926,21 @@ export class CoreLoginHelperProvider { } } + /** + * Check if the default login form should be displayed. + * + * @param config Site public config. + * @returns True if the login form should be displayed. + */ + async shouldShowLoginForm(config?: CoreSitePublicConfigResponse): Promise { + // Only hide the form if the setting exists and is set to 0. + if (config?.showloginform === 0) { + return Boolean(await CoreConfig.get(ALWAYS_SHOW_LOGIN_FORM, 0)); + } + + return true; + } + /** * Check if a confirm should be shown to open a SSO authentication. * @@ -1692,6 +1709,7 @@ declare module '@singletons/events' { * @see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation */ export interface CoreEventsData { + [ALWAYS_SHOW_LOGIN_FORM_CHANGED]: { value: number }; [APP_UNSUPPORTED_CHURN]: { siteUrl: string; debug?: CoreSiteErrorDebug }; } diff --git a/src/core/features/login/tests/behat/showloginform_setting.feature b/src/core/features/login/tests/behat/showloginform_setting.feature new file mode 100644 index 000000000..56a02a978 --- /dev/null +++ b/src/core/features/login/tests/behat/showloginform_setting.feature @@ -0,0 +1,60 @@ +@core_login @app @javascript @lms_from4.5 +Feature: Test showloginform setting in the app + + Background: + Given the Moodle site is compatible with this feature + And the following config values are set as admin: + | showloginform | 0 | + And the following "users" exist: + | username | firstname | lastname | + | student | david | student | + + Scenario: Login + When I launch the app + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + Then the header should be "Log in" in the app + And I should not find "Log in" "ion-button" in the app + And I replace "/.*/" within ".core-siteurl" with "https://campus.example.edu" + And the UI should match the snapshot + + Scenario: Reconnect + When I entered the app as "student" + And I log out in the app + And I press "david student" in the app + Then the header should be "Reconnect" in the app + And I should not find "Log in" "ion-button" in the app + And I replace "/.*/" within ".core-siteurl" with "https://campus.example.edu" + And the UI should match the snapshot + + Scenario: Login with forced developer option + When I launch the app + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + And I press "App settings" in the app + And I press "About" in the app + And I press "Moodle Mobile" in the app + And I press "Developer options" in the app + And I press "Always show login form" in the app + And I press the back button in the app + And I press the back button in the app + And I press the back button in the app + And I press the back button in the app + Then the header should be "Log in" in the app + And I should find "Log in" "ion-button" in the app + + Scenario: Reconnect with forced developer option + When I entered the app as "student" + And I log out in the app + And I press "App settings" in the app + And I press "About" in the app + And I press "Moodle Mobile" in the app + And I press "Developer options" in the app + And I press "Always show login form" in the app + And I press the back button in the app + And I press the back button in the app + And I press the back button in the app + And I press the back button in the app + And I press "david student" in the app + Then the header should be "Reconnect" in the app + And I should find "Log in" "ion-button" in the app diff --git a/src/core/features/login/tests/behat/snapshots/test-showloginform-setting-in-the-app-login_10.png b/src/core/features/login/tests/behat/snapshots/test-showloginform-setting-in-the-app-login_10.png new file mode 100644 index 0000000000000000000000000000000000000000..c31717c6490cd2d717d469534ab3ab01cbcf0c04 GIT binary patch literal 20542 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 staging sites {{stagingSitesCount}}

+ + +

Always show login form

+
+
diff --git a/src/core/features/settings/pages/dev/dev.ts b/src/core/features/settings/pages/dev/dev.ts index 8b2888399..7c9464ffd 100644 --- a/src/core/features/settings/pages/dev/dev.ts +++ b/src/core/features/settings/pages/dev/dev.ts @@ -14,12 +14,18 @@ import { CoreConstants } from '@/core/constants'; import { Component, OnInit } from '@angular/core'; -import { FAQ_QRCODE_INFO_DONE, ONBOARDING_DONE } from '@features/login/constants'; +import { + ALWAYS_SHOW_LOGIN_FORM, + ALWAYS_SHOW_LOGIN_FORM_CHANGED, + FAQ_QRCODE_INFO_DONE, + ONBOARDING_DONE, +} from '@features/login/constants'; import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; import { CoreUserTours } from '@features/usertours/services/user-tours'; import { CoreCacheManager } from '@services/cache-manager'; import { CoreConfig } from '@services/config'; +import { CoreEvents } from '@singletons/events'; import { CoreFile } from '@services/file'; import { CoreNavigator } from '@services/navigator'; import { CorePlatform } from '@services/platform'; @@ -40,6 +46,7 @@ export class CoreSettingsDevPage implements OnInit { rtl = false; forceSafeAreaMargins = false; direction = 'ltr'; + alwaysShowLoginForm = false; remoteStyles = true; remoteStylesCount = 0; @@ -70,6 +77,7 @@ export class CoreSettingsDevPage implements OnInit { this.enableStagingSites = await CoreSettingsHelper.hasEnabledStagingSites(); this.previousEnableStagingSites = this.enableStagingSites; } + this.alwaysShowLoginForm = Boolean(await CoreConfig.get(ALWAYS_SHOW_LOGIN_FORM, 0)); if (!this.siteId) { return; @@ -125,6 +133,15 @@ export class CoreSettingsDevPage implements OnInit { document.documentElement.classList.toggle('force-safe-area-margins', this.forceSafeAreaMargins); } + /** + * Called when always show login form is enabled or disabled. + */ + async alwaysShowLoginFormChanged(): Promise { + const value = Number(this.alwaysShowLoginForm); + await CoreConfig.set(ALWAYS_SHOW_LOGIN_FORM, value); + CoreEvents.trigger(ALWAYS_SHOW_LOGIN_FORM_CHANGED, { value }); + } + /** * Called when remote styles is enabled or disabled. */