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 }}
+
+
+
+
+
+
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.