MOBILE-4201 login: Move oauth and scanQR to login methods component

main
Pau Ferrer Ocaña 2023-08-25 15:03:53 +02:00
parent b8071a6946
commit ff00454e33
7 changed files with 106 additions and 136 deletions

View File

@ -1,7 +1,33 @@
<ng-container *ngIf="loginMethods?.length">
<div *ngIf="loginMethods.length || identityProviders.length || showScanQR"
class="ion-text-center ion-padding core-login-site-qrcode-separator">
{{ 'core.login.or' | translate }}
</div>
<div class="core-login-methods" *ngIf="loginMethods.length">
<ion-button [fill]="'outline'" class="ion-text-wrap ion-margin" *ngFor="let method of loginMethods" (click)="method.action()"
[attr.aria-label]="method.name" expand="block">
<ion-icon *ngIf="method.icon" [name]="method.icon" slot="start"></ion-icon>
<ion-label>{{ method.name }}</ion-label>
</ion-button>
</div>
<ng-container *ngIf="showScanQR">
<ion-button expand="block" fill="outline" class="ion-margin core-login-site-qrcode" (click)="showInstructionsAndScanQR()">
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
{{ 'core.scanqr' | translate }}
</ion-button>
</ng-container>
<!-- Identity providers. -->
<ion-list *ngIf="identityProviders.length" class="ion-padding-top core-login-identity-providers">
<ion-item class="ion-text-wrap">
<ion-label>
<h2 class="item-heading">{{ 'core.login.potentialidps' | translate }}</h2>
</ion-label>
</ion-item>
<ion-button [fill]="'outline'" *ngFor="let provider of identityProviders" class="ion-text-wrap ion-margin core-oauth-provider"
(click)="oauthClicked(provider)" [attr.aria-label]="provider.name" expand="block">
<img *ngIf="provider.iconurl" [src]="provider.iconurl" alt="" width="32" height="32" slot="start" aria-hidden="true">
<ion-label>{{ provider.name }}</ion-label>
</ion-button>
</ion-list>

View File

@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/site';
import { CoreLoginHelper, CoreLoginMethod } from '@features/login/services/login-helper';
import { CoreRedirectPayload } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
@Component({
selector: 'core-login-methods',
@ -23,18 +26,75 @@ import { CoreSites } from '@services/sites';
})
export class CoreLoginMethodsComponent implements OnInit {
loginMethods?: CoreLoginMethod[];
@Input() reconnect = false;
@Input() siteUrl = '';
@Input() siteConfig?: CoreSitePublicConfigResponse;
@Input() redirectData?: CoreRedirectPayload;
showScanQR = false;
loginMethods: CoreLoginMethod[] = [];
identityProviders: CoreSiteIdentityProvider[] = [];
/**
* @inheritdoc
*/
async ngOnInit(): Promise<void> {
this.loginMethods = await CoreLoginHelper.getLoginMethods();
const currentSite = CoreSites.getCurrentSite();
const defaultMethod = await CoreLoginHelper.getDefaultLoginMethod();
if (this.reconnect) {
this.loginMethods = await CoreLoginHelper.getLoginMethods();
if (currentSite?.isLoggedOut() && defaultMethod) {
await defaultMethod.action();
const currentSite = CoreSites.getCurrentSite();
const defaultMethod = await CoreLoginHelper.getDefaultLoginMethod();
if (currentSite?.isLoggedOut() && defaultMethod) {
await defaultMethod.action();
}
}
if (this.siteConfig) {
const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
this.identityProviders = CoreLoginHelper.getValidIdentityProviders(this.siteConfig, disabledFeatures);
if (this.reconnect) {
this.showScanQR = CoreLoginHelper.displayQRInSiteScreen();
}
// If still false or credentials screen.
if (!this.reconnect || !this.showScanQR) {
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
}
}
}
/**
* Show instructions and scan QR code.
*
* @returns Promise resolved when done.
*/
async showInstructionsAndScanQR(): Promise<void> {
try {
await CoreLoginHelper.showScanQRInstructions();
await CoreLoginHelper.scanQR();
} catch {
// Ignore errors.
}
}
/**
* An OAuth button was clicked.
*
* @param provider The provider that was clicked.
*/
oauthClicked(provider: CoreSiteIdentityProvider): void {
const result = CoreLoginHelper.openBrowserForOAuthLogin(
this.siteUrl,
provider,
this.siteConfig?.launchurl,
this.redirectData,
);
if (!result) {
CoreDomUtils.showErrorModal('Invalid data.');
}
}

View File

@ -59,14 +59,6 @@
</ion-button>
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
<input type="submit" class="core-submit-hidden-enter" />
<ng-container *ngIf="showScanQR">
<div class="ion-text-center ion-padding core-login-site-qrcode-separator">{{ 'core.login.or' | translate }}</div>
<ion-button expand="block" fill="outline" class="ion-margin core-login-site-qrcode" (click)="showInstructionsAndScanQR()">
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
{{ 'core.scanqr' | translate }}
</ion-button>
</ng-container>
</form>
<!-- Forgotten password option. -->
@ -75,18 +67,7 @@
{{ 'core.login.forgotten' | translate }}
</ion-button>
<ion-list *ngIf="identityProviders && identityProviders.length" class="ion-padding-top core-login-identity-providers">
<ion-item class="ion-text-wrap">
<ion-label>
<h2 class="item-heading">{{ 'core.login.potentialidps' | translate }}</h2>
</ion-label>
</ion-item>
<ion-button fill="outline" *ngFor="let provider of identityProviders" class="ion-text-wrap ion-margin core-oauth-provider"
(click)="oauthClicked(provider)" [attr.aria-label]="provider.name" expand="block">
<img *ngIf="provider.iconurl" [src]="provider.iconurl" alt="" width="32" height="32" slot="start" aria-hidden="true">
<ion-label>{{provider.name}}</ion-label>
</ion-button>
</ion-list>
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [siteUrl]="siteUrl"></core-login-methods>
<ion-list *ngIf="canSignup || authInstructions" class="ion-padding-top core-login-sign-up">
<ion-item class="ion-text-wrap">

View File

@ -24,7 +24,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreLoginHelper } from '@features/login/services/login-helper';
import { CoreConstants } from '@/core/constants';
import { Translate } from '@singletons';
import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/site';
import { CoreSitePublicConfigResponse } from '@classes/site';
import { CoreEvents } from '@singletons/events';
import { CoreNavigator } from '@services/navigator';
import { CoreForms } from '@singletons/form';
@ -53,7 +53,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
logoUrl?: string;
authInstructions?: string;
canSignup?: boolean;
identityProviders?: CoreSiteIdentityProvider[];
pageLoaded = false;
isBrowserSSO = false;
showForgottenPassword = true;
@ -206,7 +205,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
this.identityProviders = CoreLoginHelper.getValidIdentityProviders(this.siteConfig, disabledFeatures);
this.canSignup = this.siteConfig.registerauth == 'email' &&
!CoreLoginHelper.isEmailSignupDisabled(this.siteConfig, disabledFeatures);
this.showForgottenPassword = !CoreLoginHelper.isForgottenPasswordDisabled(this.siteConfig, disabledFeatures);
@ -222,7 +220,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
} else {
this.authInstructions = undefined;
this.canSignup = false;
this.identityProviders = [];
}
}
@ -329,32 +326,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
CoreLoginHelper.forgottenPasswordClicked(this.siteUrl, this.credForm.value.username, this.siteConfig);
}
/**
* An OAuth button was clicked.
*
* @param provider The provider that was clicked.
*/
oauthClicked(provider: CoreSiteIdentityProvider): void {
if (!CoreLoginHelper.openBrowserForOAuthLogin(this.siteUrl, provider, this.siteConfig?.launchurl)) {
CoreDomUtils.showErrorModal('Invalid data.');
}
}
/**
* Show instructions and scan QR code.
*
* @returns Promise resolved when done.
*/
async showInstructionsAndScanQR(): Promise<void> {
try {
await CoreLoginHelper.showScanQRInstructions();
await CoreLoginHelper.scanQR();
} catch {
// Ignore errors.
}
}
/**
* Open email signup page.
*/
@ -370,7 +341,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
}
/**
* View destroyed.
* @inheritdoc
*/
ngOnDestroy(): void {
this.viewLeft = true;

View File

@ -83,37 +83,11 @@
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
{{ 'core.login.forgotten' | translate }}
</ion-button>
<div class="ion-text-center ion-padding core-login-site-qrcode-separator">{{ 'core.login.or' | translate }}</div>
<!-- Login methods -->
<core-login-methods></core-login-methods>
<ng-container *ngIf="showScanQR && !isBrowserSSO">
<ion-button expand="block" fill="outline" class="ion-margin core-login-site-qrcode"
(click)="showInstructionsAndScanQR()">
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
{{ 'core.scanqr' | translate }}
</ion-button>
</ng-container>
</form>
<!-- Identity providers. -->
<ion-list *ngIf="identityProviders?.length" class="ion-padding-top core-login-identity-providers">
<ion-item class="ion-text-wrap">
<ion-label>
<h2 class="item-heading">{{ 'core.login.potentialidps' | translate }}</h2>
</ion-label>
</ion-item>
<ion-button [fill]="'outline'" *ngFor="let provider of identityProviders"
class="ion-text-wrap ion-margin core-oauth-provider" (click)="oauthClicked(provider)" [attr.aria-label]="provider.name"
expand="block">
<img *ngIf="provider.iconurl" [src]="provider.iconurl" alt="" width="32" height="32" slot="start" aria-hidden="true">
<ion-label>{{ provider.name }}</ion-label>
</ion-button>
</ion-list>
<!-- Additional Login methods -->
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [reconnect]="true" [siteUrl]="siteUrl"
[redirectData]="redirectData"></core-login-methods>
<!-- If OAuth, display cancel button since the form isn't displayed. -->
<ion-list *ngIf="isOAuth">

View File

@ -21,7 +21,7 @@ import { CoreSiteBasicInfo, CoreSites, CoreSitesReadingStrategy } from '@service
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreLoginHelper } from '@features/login/services/login-helper';
import { CoreSite, CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/site';
import { CoreSite, CoreSitePublicConfigResponse } from '@classes/site';
import { CoreEvents } from '@singletons/events';
import { CoreError } from '@classes/errors/error';
import { CoreNavigator, CoreRedirectPayload } from '@services/navigator';
@ -46,9 +46,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
credForm: FormGroup;
siteUrl!: string;
username!: string;
logoUrl?: string;
identityProviders?: CoreSiteIdentityProvider[];
showForgottenPassword = true;
showUserAvatar = false;
isBrowserSSO = false;
@ -61,12 +59,13 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
reconnectAttempts = 0;
supportConfig?: CoreUserSupportConfig;
exceededAttemptsHTML?: SafeHtml | string | null;
siteConfig?: CoreSitePublicConfigResponse;
redirectData?: CoreRedirectPayload;
protected siteConfig?: CoreSitePublicConfigResponse;
protected viewLeft = false;
protected eventThrown = false;
protected redirectData?: CoreRedirectPayload;
protected loginSuccessful = false;
protected username = '';
constructor(
protected fb: FormBuilder,
@ -127,7 +126,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
// Show logo instead of avatar if it's a fixed site.
this.showUserAvatar = !availableSites.length;
this.checkSiteConfig(site);
await this.checkSiteConfig(site);
this.showLoading = false;
} catch (error) {
@ -175,9 +174,6 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
return;
}
const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
this.identityProviders = CoreLoginHelper.getValidIdentityProviders(this.siteConfig, disabledFeatures);
this.showForgottenPassword = !CoreLoginHelper.isForgottenPasswordDisabled(this.siteConfig);
this.exceededAttemptsHTML = CoreLoginHelper.buildExceededAttemptsHTML(
!!this.supportConfig?.canContactSupport(),
@ -191,12 +187,6 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
this.isBrowserSSO = !this.isOAuth && CoreLoginHelper.isSSOLoginNeeded(this.siteConfig.typeoflogin);
this.showScanQR = CoreLoginHelper.displayQRInSiteScreen();
if (!this.showScanQR) {
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
}
await CoreSites.checkApplication(this.siteConfig);
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
@ -324,39 +314,6 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
);
}
/**
* An OAuth button was clicked.
*
* @param provider The provider that was clicked.
*/
oauthClicked(provider: CoreSiteIdentityProvider): void {
const result = CoreLoginHelper.openBrowserForOAuthLogin(
this.siteUrl,
provider,
this.siteConfig?.launchurl,
this.redirectData,
);
if (!result) {
CoreDomUtils.showErrorModal('Invalid data.');
}
}
/**
* Show instructions and scan QR code.
*
* @returns Promise resolved when done.
*/
async showInstructionsAndScanQR(): Promise<void> {
try {
await CoreLoginHelper.showScanQRInstructions();
await CoreLoginHelper.scanQR();
} catch {
// Ignore errors.
}
}
/**
* A11y key functionality that prevents keyDown events.
*

View File

@ -975,6 +975,7 @@ export class CoreLoginHelperProvider {
} else {
if (currentSite.isOAuth()) {
// User authenticated using an OAuth method. Check if it's still valid.
// @TODO Why disabledFeatures is not checked here?
const identityProviders = this.getValidIdentityProviders(result.config);
const providerToUse = identityProviders.find((provider) => {
const params = CoreUrlUtils.extractUrlParams(provider.url);