MOBILE-3565 login: Implement forgotten password page

main
Dani Palou 2020-10-27 13:16:25 +01:00
parent d66c744ab8
commit 996f1c6ae3
6 changed files with 216 additions and 14 deletions

View File

@ -37,6 +37,11 @@ const routes: Routes = [
path: 'sites',
loadChildren: () => import('./pages/sites/sites.page.module').then( m => m.CoreLoginSitesPageModule),
},
{
path: 'forgottenpassword',
loadChildren: () => import('./pages/forgotten-password/forgotten-password.module')
.then( m => m.CoreLoginForgottenPasswordPageModule),
},
];
@NgModule({

View File

@ -264,12 +264,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
* Forgotten password button clicked.
*/
forgottenPassword(): void {
CoreLoginHelper.instance.forgottenPasswordClicked(
this.navCtrl,
this.siteUrl,
this.credForm.value.username,
this.siteConfig,
);
CoreLoginHelper.instance.forgottenPasswordClicked(this.siteUrl, this.credForm.value.username, this.siteConfig);
}
/**

View File

@ -0,0 +1,41 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
</ion-buttons>
<ion-title>{{ 'core.login.passwordforgotten' | translate }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list lines="none">
<ion-item class="ion-text-wrap">
{{ 'core.login.passwordforgotteninstructions2' | translate }}
</ion-item>
</ion-list>
<ion-card>
<form ion-list [formGroup]="myForm" (ngSubmit)="resetPassword($event)" #resetPasswordForm>
<ion-item-divider class="ion-text-wrap">
{{ 'core.login.searchby' | translate }}
</ion-item-divider>
<ion-radio-group formControlName="field">
<ion-item>
<ion-label>{{ 'core.login.username' | translate }}</ion-label>
<ion-radio slot="start" value="username"></ion-radio>
</ion-item>
<ion-item>
<ion-label>{{ 'core.user.email' | translate }}</ion-label>
<ion-radio slot="start" value="email"></ion-radio>
</ion-item>
</ion-radio-group>
<ion-item>
<ion-input type="text" name="value" placeholder="{{ 'core.login.usernameoremail' | translate }}"
formControlName="value" autocapitalize="none" autocorrect="off" [core-auto-focus]="autoFocus">
</ion-input>
</ion-item>
<ion-button type="submit" class="ion-margin" expand="block" [disabled]="!myForm.valid">
{{ 'core.courses.search' | translate }}
</ion-button>
</form>
</ion-card>
</ion-content>

View File

@ -0,0 +1,47 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreLoginForgottenPasswordPage } from './forgotten-password.page';
const routes: Routes = [
{
path: '',
component: CoreLoginForgottenPasswordPage,
},
];
@NgModule({
imports: [
RouterModule.forChild(routes),
CommonModule,
IonicModule,
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreDirectivesModule,
],
declarations: [
CoreLoginForgottenPasswordPage,
],
exports: [RouterModule],
})
export class CoreLoginForgottenPasswordPageModule {}

View File

@ -0,0 +1,120 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, ViewChild, ElementRef, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NavController } from '@ionic/angular';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreLoginHelper } from '@core/login/services/helper';
import { Translate, Platform } from '@singletons/core.singletons';
import { CoreWSExternalWarning } from '@services/ws';
/**
* Page to recover a forgotten password.
*/
@Component({
selector: 'page-core-login-forgotten-password',
templateUrl: 'forgotten-password.html',
})
export class CoreLoginForgottenPasswordPage implements OnInit {
@ViewChild('resetPasswordForm') formElement?: ElementRef;
myForm!: FormGroup;
siteUrl!: string;
autoFocus!: boolean;
constructor(
protected navCtrl: NavController,
protected formBuilder: FormBuilder,
protected route: ActivatedRoute,
) {
}
/**
* Initialize the component.
*/
ngOnInit(): void {
const params = this.route.snapshot.queryParams;
this.siteUrl = params['siteUrl'];
this.autoFocus = Platform.instance.is('tablet');
this.myForm = this.formBuilder.group({
field: ['username', Validators.required],
value: [params['username'] || '', Validators.required],
});
}
/**
* Request to reset the password.
*
* @param e Event.
*/
async resetPassword(e: Event): Promise<void> {
e.preventDefault();
e.stopPropagation();
const field = this.myForm.value.field;
const value = this.myForm.value.value;
if (!value) {
CoreDomUtils.instance.showErrorModal('core.login.usernameoremail', true);
return;
}
const modal = await CoreDomUtils.instance.showModalLoading('core.sending', true);
const isMail = field == 'email';
try {
const response = await CoreLoginHelper.instance.requestPasswordReset(
this.siteUrl,
isMail ? '' : value,
isMail ? value : '',
);
if (response.status == 'dataerror') {
// Error in the data sent.
this.showError(isMail, response.warnings!);
} else if (response.status == 'emailpasswordconfirmnotsent' || response.status == 'emailpasswordconfirmnoemail') {
// Error, not found.
CoreDomUtils.instance.showErrorModal(response.notice);
} else {
// Success.
CoreDomUtils.instance.triggerFormSubmittedEvent(this.formElement, true);
CoreDomUtils.instance.showAlert(Translate.instance.instant('core.success'), response.notice);
this.navCtrl.pop();
}
} catch (error) {
CoreDomUtils.instance.showErrorModal(error);
} finally {
modal.dismiss();
}
}
// Show an error from the warnings.
protected showError(isMail: boolean, warnings: CoreWSExternalWarning[]): void {
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i];
if ((warning.item == 'email' && isMail) || (warning.item == 'username' && !isMail)) {
CoreDomUtils.instance.showErrorModal(warning.message);
break;
}
}
}
}

View File

@ -163,12 +163,7 @@ export class CoreLoginHelperProvider {
* @param username Username.
* @param siteConfig Site config.
*/
async forgottenPasswordClicked(
navCtrl: NavController,
siteUrl: string,
username: string,
siteConfig?: CoreSitePublicConfigResponse,
): Promise<void> {
async forgottenPasswordClicked(siteUrl: string, username: string, siteConfig?: CoreSitePublicConfigResponse): Promise<void> {
if (siteConfig && siteConfig.forgottenpasswordurl) {
// URL set, open it.
CoreUtils.instance.openInApp(siteConfig.forgottenpasswordurl);
@ -183,7 +178,7 @@ export class CoreLoginHelperProvider {
const canReset = await this.canRequestPasswordReset(siteUrl);
if (canReset) {
await navCtrl.navigateForward(['/login/forgottenpassword'], {
await this.navCtrl.navigateForward(['/login/forgottenpassword'], {
queryParams: {
siteUrl,
username,
@ -445,7 +440,6 @@ export class CoreLoginHelperProvider {
/**
* Open a page that doesn't belong to any site.
*
* @param navCtrl Nav Controller.
* @param page Page to open.
* @param params Params of the page.
* @return Promise resolved when done.