Skip to content

Commit

Permalink
MOBILE-4631 login: Hide the login form in the app when is hidden in LMS
Browse files Browse the repository at this point in the history
  • Loading branch information
albertgasset committed Aug 5, 2024
1 parent a7536cc commit 357fda7
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/core/classes/sites/unauthenticated-site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
};

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<div *ngIf="loginMethods.length || identityProviders.length || showScanQR" class="ion-text-center ion-padding core-login-methods-separator">
<div *ngIf="(showLoginForm || isBrowserSSO) && (loginMethods.length || identityProviders.length || showScanQR)"
class="ion-text-center ion-padding core-login-methods-separator">
<span>{{ 'core.login.or' | translate }}</span>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class CoreLoginMethodsComponent implements OnInit {
@Input() siteUrl = '';
@Input() siteConfig?: CoreSitePublicConfigResponse;
@Input() redirectData?: CoreRedirectPayload;
@Input() showLoginForm = true;

isBrowserSSO = false;
showScanQR = false;
Expand Down
2 changes: 2 additions & 0 deletions src/core/features/login/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
5 changes: 3 additions & 2 deletions src/core/features/login/pages/credentials/credentials.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ <h2 *ngIf="siteName" class="ion-margin-top ion-no-padding core-sitename">
</div>

<div class="core-login-methods">
<form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm *ngIf="!isBrowserSSO">
<form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm
*ngIf="showLoginForm && !isBrowserSSO">
<ion-item class="ion-margin-bottom" lines="inset">
<ion-input type="text" name="username" placeholder="{{ 'core.login.username' | translate }}"
formControlName="username" autocapitalize="none" autocorrect="off" autocomplete="username" enterkeyhint="next"
Expand Down Expand Up @@ -80,7 +81,7 @@ <h2 *ngIf="siteName" class="ion-margin-top ion-no-padding core-sitename">
</ng-container>


<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [siteUrl]="site.siteUrl" />
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [siteUrl]="site.siteUrl" [showLoginForm]="showLoginForm" />
</div>

<div class="core-login-sign-up" *ngIf="!isBrowserSSO && (canSignup || authInstructions)">
Expand Down
17 changes: 15 additions & 2 deletions src/core/features/login/pages/credentials/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -66,13 +70,15 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
siteConfig?: CoreSitePublicConfigResponse;
siteCheckError = '';
displaySiteUrl = false;
showLoginForm = true;

protected siteCheck?: CoreSiteCheckResponse;
protected eventThrown = false;
protected viewLeft = false;
protected siteId?: string;
protected urlToOpen?: string;
protected valueChangeSubscription?: Subscription;
protected alwaysShowLoginFormObserver?: CoreEventObserver;

constructor(
protected fb: FormBuilder,
Expand Down Expand Up @@ -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);
});
}

/**
Expand Down Expand Up @@ -191,6 +201,8 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
* Treat the site configuration (if it exists).
*/
protected async treatSiteConfig(): Promise<void> {
this.showLoginForm = await CoreLoginHelper.shouldShowLoginForm(this.siteConfig);

if (!this.siteConfig) {
this.authInstructions = undefined;
this.canSignup = false;
Expand Down Expand Up @@ -365,6 +377,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
this.siteId,
);
this.valueChangeSubscription?.unsubscribe();
this.alwaysShowLoginFormObserver?.off();
}

}
5 changes: 3 additions & 2 deletions src/core/features/login/pages/reconnect/reconnect.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ <h1>{{ 'core.login.reconnect' | translate }}</h1>
</div>

<div class="core-login-methods">
<form *ngIf="!isBrowserSSO" [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #reconnectForm>
<form *ngIf="showLoginForm && !isBrowserSSO" [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form"
#reconnectForm>
<ion-item class="ion-margin-bottom" lines="inset">
<ion-input class="core-ioninput-password" name="password" type="password"
placeholder="{{ 'core.login.password' | translate }}" formControlName="password" [clearOnEdit]="false"
Expand Down Expand Up @@ -91,7 +92,7 @@ <h1>{{ 'core.login.reconnect' | translate }}</h1>

<!-- Additional Login methods -->
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [reconnect]="true" [siteUrl]="site.siteUrl"
[redirectData]="redirectData" />
[redirectData]="redirectData" [showLoginForm]="showLoginForm" />
</div>
</div>
</core-loading>
Expand Down
13 changes: 11 additions & 2 deletions src/core/features/login/pages/reconnect/reconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';

/**
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -147,6 +153,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
},
this.siteId,
);
this.alwaysShowLoginFormObserver?.off();
}

/**
Expand All @@ -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;
}
Expand Down
18 changes: 18 additions & 0 deletions src/core/features/login/services/login-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<boolean> {
// 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.
*
Expand Down Expand Up @@ -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 };
}

Expand Down
60 changes: 60 additions & 0 deletions src/core/features/login/tests/behat/showloginform_setting.feature
Original file line number Diff line number Diff line change
@@ -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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/core/features/settings/pages/dev/dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ <h1>{{ 'core.settings.developeroptions' | translate }}</h1>
<p class="item-heading">Enable staging sites <ion-badge>{{stagingSitesCount}}</ion-badge></p>
</ion-toggle>
</ion-item>
<ion-item class="ion-text-wrap">
<ion-toggle [(ngModel)]="alwaysShowLoginForm" (ionChange)="alwaysShowLoginFormChanged()">
<p class="item-heading">Always show login form</p>
</ion-toggle>
</ion-item>
<ng-container *ngIf="siteId">
<ion-item class="ion-text-wrap">
<ion-toggle [(ngModel)]="remoteStyles" (ionChange)="remoteStylesChanged()">
Expand Down
19 changes: 18 additions & 1 deletion src/core/features/settings/pages/dev/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -40,6 +46,7 @@ export class CoreSettingsDevPage implements OnInit {
rtl = false;
forceSafeAreaMargins = false;
direction = 'ltr';
alwaysShowLoginForm = false;

remoteStyles = true;
remoteStylesCount = 0;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<void> {
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.
*/
Expand Down

0 comments on commit 357fda7

Please sign in to comment.