From 996f1c6ae34eb08fe6606cc94664dc6d23f3cc11 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 27 Oct 2020 13:16:25 +0100 Subject: [PATCH] MOBILE-3565 login: Implement forgotten password page --- src/app/core/login/login-routing.module.ts | 5 + .../pages/credentials/credentials.page.ts | 7 +- .../forgotten-password.html | 41 ++++++ .../forgotten-password.module.ts | 47 +++++++ .../forgotten-password.page.ts | 120 ++++++++++++++++++ src/app/core/login/services/helper.ts | 10 +- 6 files changed, 216 insertions(+), 14 deletions(-) create mode 100644 src/app/core/login/pages/forgotten-password/forgotten-password.html create mode 100644 src/app/core/login/pages/forgotten-password/forgotten-password.module.ts create mode 100644 src/app/core/login/pages/forgotten-password/forgotten-password.page.ts diff --git a/src/app/core/login/login-routing.module.ts b/src/app/core/login/login-routing.module.ts index 384546ba8..393e2f432 100644 --- a/src/app/core/login/login-routing.module.ts +++ b/src/app/core/login/login-routing.module.ts @@ -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({ diff --git a/src/app/core/login/pages/credentials/credentials.page.ts b/src/app/core/login/pages/credentials/credentials.page.ts index 8ff4ad4e2..c1a88c838 100644 --- a/src/app/core/login/pages/credentials/credentials.page.ts +++ b/src/app/core/login/pages/credentials/credentials.page.ts @@ -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); } /** diff --git a/src/app/core/login/pages/forgotten-password/forgotten-password.html b/src/app/core/login/pages/forgotten-password/forgotten-password.html new file mode 100644 index 000000000..0806d2b59 --- /dev/null +++ b/src/app/core/login/pages/forgotten-password/forgotten-password.html @@ -0,0 +1,41 @@ + + + + + + + {{ 'core.login.passwordforgotten' | translate }} + + + + + + {{ 'core.login.passwordforgotteninstructions2' | translate }} + + + +
+ + {{ 'core.login.searchby' | translate }} + + + + {{ 'core.login.username' | translate }} + + + + {{ 'core.user.email' | translate }} + + + + + + + + + {{ 'core.courses.search' | translate }} + +
+
+
diff --git a/src/app/core/login/pages/forgotten-password/forgotten-password.module.ts b/src/app/core/login/pages/forgotten-password/forgotten-password.module.ts new file mode 100644 index 000000000..360ab60b5 --- /dev/null +++ b/src/app/core/login/pages/forgotten-password/forgotten-password.module.ts @@ -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 {} diff --git a/src/app/core/login/pages/forgotten-password/forgotten-password.page.ts b/src/app/core/login/pages/forgotten-password/forgotten-password.page.ts new file mode 100644 index 000000000..8e0c357a0 --- /dev/null +++ b/src/app/core/login/pages/forgotten-password/forgotten-password.page.ts @@ -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 { + 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; + } + } + } + +} diff --git a/src/app/core/login/services/helper.ts b/src/app/core/login/services/helper.ts index 1d48d43fd..5bc26dad5 100644 --- a/src/app/core/login/services/helper.ts +++ b/src/app/core/login/services/helper.ts @@ -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 { + async forgottenPasswordClicked(siteUrl: string, username: string, siteConfig?: CoreSitePublicConfigResponse): Promise { 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.