feat: migrate login, logout, and auth guards to Django Rest
This commit is contained in:
parent
4b795ae977
commit
93000fd4c7
11 changed files with 457 additions and 366 deletions
|
|
@ -5,7 +5,7 @@ import { FormBtnComponent } from '../../../shared/components/buttons/form-btn/fo
|
||||||
import { FooterComponent } from '../footer/footer.component';
|
import { FooterComponent } from '../footer/footer.component';
|
||||||
import { HeaderComponent } from '../header/header.component';
|
import { HeaderComponent } from '../header/header.component';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoginService } from '../../../services/auth.service';
|
import { LoginService } from '../../../services/login.service';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
import { SharedService } from '../../../services/shared.service';
|
||||||
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { FooterComponent } from '../../footer/footer.component';
|
||||||
import { HeaderComponent } from '../../header/header.component';
|
import { HeaderComponent } from '../../header/header.component';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { FirebaseService } from '../../../../services/firebase.service';
|
import { FirebaseService } from '../../../../services/firebase.service';
|
||||||
import { LoginService } from '../../../../services/auth.service';
|
import { LoginService } from '../../../../services/login.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { SharedService } from '../../../../services/shared.service';
|
import { SharedService } from '../../../../services/shared.service';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
placeholder="{{ 'login.email' | translate }}"
|
placeholder="{{ 'login.email' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
[(ngModel)]="loginData.mail"
|
[(ngModel)]="loginData.email"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@if(!loginData.mail) {
|
@if(!loginData.email) {
|
||||||
<img
|
<img
|
||||||
class="custom-img"
|
class="custom-img"
|
||||||
src="./../../../assets/img/login/mail.svg"
|
src="./../../../assets/img/login/mail.svg"
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
!sharedService.isBtnDisabled) {
|
!sharedService.isBtnDisabled) {
|
||||||
<p>{{ "login.errorMail1" | translate }}</p>
|
<p>{{ "login.errorMail1" | translate }}</p>
|
||||||
} @if (mail.valid && mail.touched &&
|
} @if (mail.valid && mail.touched &&
|
||||||
!checkIfUserEmailIsValid(loginData.mail.toLowerCase()) &&
|
!checkIfUserEmailIsValid(loginData.email.toLowerCase()) &&
|
||||||
!sharedService.isBtnDisabled) {
|
!sharedService.isBtnDisabled) {
|
||||||
<p>{{ "login.errorMail2" | translate }}</p>
|
<p>{{ "login.errorMail2" | translate }}</p>
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +87,7 @@
|
||||||
}}</a>
|
}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<div class="google-button">
|
<div class="google-button">
|
||||||
<app-form-btn
|
<app-form-btn
|
||||||
[class]="'btn-google'"
|
[class]="'btn-google'"
|
||||||
|
|
@ -96,6 +97,7 @@
|
||||||
(click)="googleLogin()"
|
(click)="googleLogin()"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<app-form-btn
|
<app-form-btn
|
||||||
[class]="'btn-login'"
|
[class]="'btn-login'"
|
||||||
|
|
@ -103,11 +105,11 @@
|
||||||
[value]="'login.login' | translate"
|
[value]="'login.login' | translate"
|
||||||
[disabled]="
|
[disabled]="
|
||||||
mail.invalid ||
|
mail.invalid ||
|
||||||
!loginData.mail ||
|
!loginData.email ||
|
||||||
password.invalid ||
|
password.invalid ||
|
||||||
!loginData.password ||
|
!loginData.password ||
|
||||||
sharedService.isBtnDisabled ||
|
sharedService.isBtnDisabled ||
|
||||||
!checkIfUserEmailIsValid(loginData.mail)
|
!checkIfUserEmailIsValid(loginData.email)
|
||||||
"
|
"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
<app-form-btn
|
<app-form-btn
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { FormBtnComponent } from '../../shared/components/buttons/form-btn/form-btn.component';
|
import { FormBtnComponent } from '../../shared/components/buttons/form-btn/form-btn.component';
|
||||||
import { FirebaseService } from '../../services/firebase.service';
|
import { FirebaseService } from '../../services/firebase.service';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
import { LoginService } from '../../services/auth.service';
|
import { LoginService } from '../../services/login.service';
|
||||||
import { SharedService } from '../../services/shared.service';
|
import { SharedService } from '../../services/shared.service';
|
||||||
import { FooterComponent } from './footer/footer.component';
|
import { FooterComponent } from './footer/footer.component';
|
||||||
import { HeaderComponent } from './header/header.component';
|
import { HeaderComponent } from './header/header.component';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoadingDialogComponent } from './loading-dialog/loading-dialog.component';
|
import { LoadingDialogComponent } from './loading-dialog/loading-dialog.component';
|
||||||
import { OverlayService } from '../../services/overlay.service';
|
import { OverlayService } from '../../services/overlay.service';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
|
@ -32,12 +33,12 @@ export class LoginComponent {
|
||||||
isPasswordIconVisible: boolean = true;
|
isPasswordIconVisible: boolean = true;
|
||||||
|
|
||||||
loginData = {
|
loginData = {
|
||||||
mail: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private firebaseService: FirebaseService,
|
private authService: AuthService,
|
||||||
public loginService: LoginService,
|
public loginService: LoginService,
|
||||||
public sharedService: SharedService,
|
public sharedService: SharedService,
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
|
|
@ -46,9 +47,6 @@ export class LoginComponent {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.loginService.checkAuthUser()) {
|
|
||||||
this.router.navigate(['/summary']);
|
|
||||||
}
|
|
||||||
this.routeParams();
|
this.routeParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,16 +61,21 @@ export class LoginComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(ngForm: NgForm) {
|
async onSubmit(ngForm: NgForm) {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.sharedService.isBtnDisabled = true;
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
this.loginService.login(this.loginData);
|
try {
|
||||||
|
await this.authService.login(this.loginData, true);
|
||||||
|
this.router.navigate(['/summary']);
|
||||||
|
} catch (error) {
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guestLogin() {
|
guestLogin() {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.sharedService.isBtnDisabled = true;
|
||||||
this.loginData.mail = 'guest@guestaccount.com';
|
this.loginData.email = 'guest@guestaccount.com';
|
||||||
this.loginData.password = 'guest@guestaccount.com';
|
this.loginData.password = 'guest@guestaccount.com';
|
||||||
this.isPasswordIconVisible = !this.isPasswordIconVisible;
|
this.isPasswordIconVisible = !this.isPasswordIconVisible;
|
||||||
this.onSubmit({ submitted: true, form: { valid: true } } as NgForm);
|
this.onSubmit({ submitted: true, form: { valid: true } } as NgForm);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormBtnComponent } from '../../../shared/components/buttons/form-btn/form-btn.component';
|
import { FormBtnComponent } from '../../../shared/components/buttons/form-btn/form-btn.component';
|
||||||
import { FirebaseService } from '../../../services/firebase.service';
|
import { FirebaseService } from '../../../services/firebase.service';
|
||||||
import { LoginService } from '../../../services/auth.service';
|
import { LoginService } from '../../../services/login.service';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
import { SharedService } from '../../../services/shared.service';
|
||||||
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
import { catchError, map, Observable, of } from 'rxjs';
|
||||||
import { LoginService } from '../services/auth.service';
|
import { AuthService } from '../services/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthenticatedGuard {
|
export class AuthenticatedGuard {
|
||||||
constructor(private loginService: LoginService, private router: Router) {}
|
constructor(private authService: AuthService, private router: Router) {}
|
||||||
|
|
||||||
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
|
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
|
||||||
return this.loginService.checkAuthUser().pipe(
|
const authToken = this.authService.checkAuthToken();
|
||||||
|
if (!authToken) {
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.authService.checkAuthUser().pipe(
|
||||||
map((isAuthenticated) => {
|
map((isAuthenticated) => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,21 @@ import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { map, catchError } from 'rxjs/operators';
|
import { map, catchError } from 'rxjs/operators';
|
||||||
import { LoginService } from '../services/auth.service';
|
import { AuthService } from '../services/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class RedirectIfAuthenticatedGuard {
|
export class RedirectIfAuthenticatedGuard {
|
||||||
constructor(private loginService: LoginService, private router: Router) {}
|
constructor(private authService: AuthService, private router: Router) {}
|
||||||
|
|
||||||
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
|
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
|
||||||
return this.loginService.checkAuthUser().pipe(
|
const authToken = this.authService.checkAuthToken();
|
||||||
|
if (!authToken) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.authService.checkAuthUser().pipe(
|
||||||
map((isAuthenticated) => {
|
map((isAuthenticated) => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
this.router.navigate(['/summary']);
|
this.router.navigate(['/summary']);
|
||||||
|
|
|
||||||
390
src/app/services/auth.service.ts
Normal file → Executable file
390
src/app/services/auth.service.ts
Normal file → Executable file
|
|
@ -1,361 +1,73 @@
|
||||||
import { Injectable, inject } from '@angular/core';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import {
|
import { Injectable } from '@angular/core';
|
||||||
getAuth,
|
import { catchError, lastValueFrom, map, Observable, of } from 'rxjs';
|
||||||
signInWithEmailAndPassword,
|
import { apiConfig } from '../environments/config';
|
||||||
signInWithPopup,
|
|
||||||
GoogleAuthProvider,
|
|
||||||
createUserWithEmailAndPassword,
|
|
||||||
sendPasswordResetEmail,
|
|
||||||
confirmPasswordReset,
|
|
||||||
} from 'firebase/auth';
|
|
||||||
import { FirebaseService } from './firebase.service';
|
|
||||||
import {
|
|
||||||
Firestore,
|
|
||||||
addDoc,
|
|
||||||
collection,
|
|
||||||
doc,
|
|
||||||
getDocs,
|
|
||||||
query,
|
|
||||||
updateDoc,
|
|
||||||
where,
|
|
||||||
} from '@angular/fire/firestore';
|
|
||||||
import { SharedService } from './shared.service';
|
|
||||||
import { User } from '../interfaces/user.interface';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import CryptoES from 'crypto-es';
|
|
||||||
import { CryptoESSecretKey } from '../environments/config';
|
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class LoginService {
|
export class AuthService {
|
||||||
firestore: Firestore = inject(Firestore);
|
private apiUrl = apiConfig.apiUrl;
|
||||||
passwordFieldType: string = 'password';
|
|
||||||
passwordIcon: string = './../../../assets/img/login/close-eye.svg';
|
|
||||||
errorCode: string = '';
|
|
||||||
|
|
||||||
private secretKey: string = CryptoESSecretKey.secretKey;
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
constructor(
|
async login(body: any, storage: boolean) {
|
||||||
private firebaseService: FirebaseService,
|
const data = (await lastValueFrom(
|
||||||
public sharedService: SharedService,
|
this.http.post(`${this.apiUrl}/auth/login/`, body)
|
||||||
private router: Router
|
)) as { token: string };
|
||||||
) {}
|
this.storeAuthToken(data.token, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout() {
|
||||||
|
const token = this.checkAuthToken();
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
await lastValueFrom(
|
||||||
|
this.http.post(
|
||||||
|
`${this.apiUrl}/auth/logout/`,
|
||||||
|
{},
|
||||||
|
{ headers: { Authorization: `Token ${token}` } }
|
||||||
|
)
|
||||||
|
).catch((error) => console.error('Logout failed:', error));
|
||||||
|
|
||||||
|
this.deleteAuthToken();
|
||||||
|
window.location.href = '/login';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a user is logged in.
|
|
||||||
*
|
|
||||||
* @returns An Observable resolving to a boolean indicating whether a user is logged in.
|
|
||||||
*/
|
|
||||||
checkAuthUser(): Observable<boolean> {
|
checkAuthUser(): Observable<boolean> {
|
||||||
return this.firebaseService.getAuthUser().pipe(
|
const headers = this.getAuthHeaders();
|
||||||
map((user) => {
|
return this.http.get<any>(`${this.apiUrl}/auth/`, { headers }).pipe(
|
||||||
if (user) {
|
map(() => {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
catchError(() => {
|
catchError(() => of(false))
|
||||||
return of(false);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private getAuthHeaders(): HttpHeaders {
|
||||||
* Logs in a user given their email and password.
|
let authToken = localStorage.getItem('authToken');
|
||||||
* @param loginData An object with properties `mail` and `password`.
|
if (!authToken) {
|
||||||
* @returns A Promise resolving to void.
|
authToken = sessionStorage.getItem('authToken');
|
||||||
* @throws An error if the login attempt fails.
|
|
||||||
*/
|
|
||||||
login(loginData: { mail: string; password: string }) {
|
|
||||||
signInWithEmailAndPassword(getAuth(), loginData.mail, loginData.password)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
const userData = this.firebaseService.getUserDataFromUid(user.uid);
|
|
||||||
if (userData.length > 0 && userData[0].id) {
|
|
||||||
this.getUserIdInLocalStorage(userData[0].id);
|
|
||||||
this.updateUserOnlineStatus(userData[0].id, true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorCode = error.code;
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a new user given their name, first name, last name, email and password.
|
|
||||||
* @param registerData An object with properties `name`, `firstName`, `lastName`, `mail` and `password`.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
* @throws An error if the registration attempt fails.
|
|
||||||
*/
|
|
||||||
register(registerData: {
|
|
||||||
name: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
mail: string;
|
|
||||||
password: string;
|
|
||||||
}) {
|
|
||||||
createUserWithEmailAndPassword(
|
|
||||||
getAuth(),
|
|
||||||
registerData.mail,
|
|
||||||
registerData.password
|
|
||||||
)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
|
|
||||||
const userDataToSave: User = {
|
|
||||||
uId: user.uid,
|
|
||||||
email: user.email || '',
|
|
||||||
firstName: registerData.firstName
|
|
||||||
? registerData.firstName.charAt(0).toUpperCase() +
|
|
||||||
registerData.firstName.slice(1)
|
|
||||||
: '',
|
|
||||||
lastName: registerData.lastName
|
|
||||||
? registerData.lastName.charAt(0).toUpperCase() +
|
|
||||||
registerData.lastName.slice(1)
|
|
||||||
: '',
|
|
||||||
status: true,
|
|
||||||
phone: '',
|
|
||||||
initials: registerData.name
|
|
||||||
? registerData.firstName.slice(0, 1).toUpperCase() +
|
|
||||||
registerData.lastName.slice(0, 1).toUpperCase()
|
|
||||||
: '',
|
|
||||||
color: this.sharedService.generateRandomColor(),
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
};
|
|
||||||
this.createUserInFirestore(userDataToSave);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Google login method.
|
|
||||||
*
|
|
||||||
* Signs in the user with Google Authentication.
|
|
||||||
* If the user is not in the database, creates a new user with the provided name and email.
|
|
||||||
* If the user is already in the database, logins the user.
|
|
||||||
*
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
* @memberof LoginService
|
|
||||||
*/
|
|
||||||
googleLogin() {
|
|
||||||
const auth = getAuth();
|
|
||||||
const provider = new GoogleAuthProvider();
|
|
||||||
|
|
||||||
signInWithPopup(auth, provider)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
const usersCollection = collection(this.firestore, 'users');
|
|
||||||
const querySnapshot = query(
|
|
||||||
usersCollection,
|
|
||||||
where('uId', '==', user.uid)
|
|
||||||
);
|
|
||||||
getDocs(querySnapshot).then((snapshot) => {
|
|
||||||
if (snapshot.empty) {
|
|
||||||
const displayName = user.displayName || '';
|
|
||||||
const [firstName = '', lastName = ''] = displayName.split(' ');
|
|
||||||
this.createUserInFirestore({
|
|
||||||
uId: user.uid,
|
|
||||||
email: user.email || 'no mail',
|
|
||||||
firstName: firstName.charAt(0).toUpperCase() + firstName.slice(1),
|
|
||||||
lastName: lastName.charAt(0).toUpperCase() + lastName.slice(1),
|
|
||||||
status: true,
|
|
||||||
phone: '',
|
|
||||||
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
|
||||||
color: this.sharedService.generateRandomColor(),
|
|
||||||
lastLogin: 0,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.ifExistUser(user.uid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new user in the Firestore database with the given user data.
|
|
||||||
* If the user already exists in the database, the method does nothing.
|
|
||||||
* @param user The user data to save. The user data should contain the following properties: `uId`, `email`, `firstName`, `lastName`, `initials`, `color`.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
*/
|
|
||||||
async createUserInFirestore(user: User) {
|
|
||||||
const userDataToSave: User = {
|
|
||||||
uId: user.uId,
|
|
||||||
email: user.email,
|
|
||||||
firstName: user.firstName || '',
|
|
||||||
lastName: user.lastName || '',
|
|
||||||
status: true,
|
|
||||||
phone: '',
|
|
||||||
initials: user.initials,
|
|
||||||
color: user.color,
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
};
|
|
||||||
const usersCollection = collection(this.firestore, 'users');
|
|
||||||
try {
|
|
||||||
const docRef = await addDoc(usersCollection, userDataToSave);
|
|
||||||
this.ifExistUser(user.uId);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
}
|
||||||
}
|
return new HttpHeaders({
|
||||||
|
Authorization: `Token ${authToken}`,
|
||||||
/**
|
|
||||||
* Checks if a user with the given user id exists in the database.
|
|
||||||
* If the user exists, the method saves the user's id in the local storage and
|
|
||||||
* updates the user's online status in the database.
|
|
||||||
* @param user The id of the user to check.
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
ifExistUser(user: string) {
|
|
||||||
const userData = this.firebaseService.getUserDataFromUid(user);
|
|
||||||
if (userData.length > 0 && userData[0].id) {
|
|
||||||
this.getUserIdInLocalStorage(userData[0].id);
|
|
||||||
this.updateUserOnlineStatus(userData[0].id, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the online status of the user with the given id in the Firestore database.
|
|
||||||
* If the user's status is set to true, the user's lastLogin property is also updated
|
|
||||||
* to the current time.
|
|
||||||
* @param userId The id of the user to update.
|
|
||||||
* @param status The new online status of the user.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
*/
|
|
||||||
async updateUserOnlineStatus(userId: string, status: boolean) {
|
|
||||||
await updateDoc(doc(collection(this.firestore, 'users'), userId), {
|
|
||||||
status: status,
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
});
|
});
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private storeAuthToken(data: any, storage: boolean) {
|
||||||
* Toggles the visibility of the password field.
|
storage
|
||||||
*
|
? localStorage.setItem('authToken', data.toString())
|
||||||
* This function switches the input type between 'password' and 'text',
|
: sessionStorage.setItem('authToken', data.toString());
|
||||||
* allowing the user to view or hide the password as needed.
|
|
||||||
* It also updates the icon to reflect the current visibility state.
|
|
||||||
*/
|
|
||||||
togglePasswordVisibility() {
|
|
||||||
this.passwordFieldType =
|
|
||||||
this.passwordFieldType === 'password' ? 'text' : 'password';
|
|
||||||
this.toggleIcon();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private deleteAuthToken() {
|
||||||
* Toggles the password visibility icon.
|
localStorage.removeItem('authToken');
|
||||||
*
|
sessionStorage.removeItem('authToken');
|
||||||
* This function switches the icon src between the 'close eye' and 'open eye'
|
|
||||||
* icons, indicating whether the password is hidden or visible.
|
|
||||||
*/
|
|
||||||
toggleIcon() {
|
|
||||||
this.passwordIcon =
|
|
||||||
this.passwordIcon === './../../../assets/img/login/close-eye.svg'
|
|
||||||
? './../../../assets/img/login/open-eye.svg'
|
|
||||||
: './../../../assets/img/login/close-eye.svg';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
checkAuthToken(): string | null {
|
||||||
* Saves the given userId to local storage, encrypted with the secret key.
|
return (
|
||||||
*
|
localStorage.getItem('authToken') || sessionStorage.getItem('authToken')
|
||||||
* The userId is first stringified and then encrypted with the secret key.
|
);
|
||||||
* The encrypted string is then saved to local storage under the key
|
|
||||||
* 'currentUserJOIN'. Additionally, the current timestamp is saved to local
|
|
||||||
* storage under the key 'sessionTimeJOIN'.
|
|
||||||
*
|
|
||||||
* @param userId The id of the user to be saved.
|
|
||||||
*/
|
|
||||||
getUserIdInLocalStorage(userId: string): void {
|
|
||||||
const encryptedValue = CryptoES.AES.encrypt(
|
|
||||||
JSON.stringify(userId),
|
|
||||||
this.secretKey
|
|
||||||
).toString();
|
|
||||||
localStorage.setItem('currentUserJOIN', encryptedValue);
|
|
||||||
localStorage.setItem('sessionTimeJOIN', new Date().getTime().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOGOUT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs out the current user by deleting the user ID from local storage and
|
|
||||||
* updating the user's online status to offline in the Firestore database.
|
|
||||||
*
|
|
||||||
* @param userId The id of the user to log out.
|
|
||||||
*/
|
|
||||||
logout(userId: string) {
|
|
||||||
this.deleteUserIdInLocalStorage();
|
|
||||||
this.updateUserOnlineStatus(userId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the user ID from local storage, effectively logging the user out.
|
|
||||||
*
|
|
||||||
* This function removes the user ID from local storage by deleting the
|
|
||||||
* 'currentUserJOIN' and 'sessionTimeJOIN' items.
|
|
||||||
*/
|
|
||||||
deleteUserIdInLocalStorage() {
|
|
||||||
localStorage.removeItem('currentUserJOIN');
|
|
||||||
localStorage.removeItem('sessionTimeJOIN');
|
|
||||||
}
|
|
||||||
|
|
||||||
// FORGOT PASSWORD
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates the password reset process for the given email address.
|
|
||||||
*
|
|
||||||
* This function sends a password reset email to the specified email address
|
|
||||||
* using Firebase Authentication. Upon successful sending of the email, the
|
|
||||||
* user is redirected to the password reset notice page. If there is an error,
|
|
||||||
* the button will be re-enabled for the user to try again.
|
|
||||||
*
|
|
||||||
* @param email The email address of the user requesting a password reset.
|
|
||||||
*/
|
|
||||||
passwordReset(email: string) {
|
|
||||||
const auth = getAuth();
|
|
||||||
const actionCodeSettings = {
|
|
||||||
url: 'https://join.andre-kempf.com/',
|
|
||||||
handleCodeInApp: true,
|
|
||||||
};
|
|
||||||
sendPasswordResetEmail(auth, email, actionCodeSettings)
|
|
||||||
.then(() => {
|
|
||||||
this.router.navigate(['/login/notice/pw-send']);
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the user's password given the new password and the oobCode from the
|
|
||||||
* password reset email.
|
|
||||||
*
|
|
||||||
* This function sends a request to Firebase Authentication to reset the user's
|
|
||||||
* password. If the request is successful, it navigates to the password reset
|
|
||||||
* notice page and re-enables the submit button. If there is an error, the
|
|
||||||
* button will be re-enabled for the user to try again.
|
|
||||||
*
|
|
||||||
* @param newPW The new password to be set for the user.
|
|
||||||
* @param oobCode The one-time code from the password reset email.
|
|
||||||
*/
|
|
||||||
newPassword(newPW: string, oobCode: string) {
|
|
||||||
const auth = getAuth();
|
|
||||||
confirmPasswordReset(auth, oobCode, newPW)
|
|
||||||
.then(() => {
|
|
||||||
this.router.navigate(['/login/notice/pw-change']);
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
361
src/app/services/login.service.ts
Normal file
361
src/app/services/login.service.ts
Normal file
|
|
@ -0,0 +1,361 @@
|
||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import {
|
||||||
|
getAuth,
|
||||||
|
signInWithEmailAndPassword,
|
||||||
|
signInWithPopup,
|
||||||
|
GoogleAuthProvider,
|
||||||
|
createUserWithEmailAndPassword,
|
||||||
|
sendPasswordResetEmail,
|
||||||
|
confirmPasswordReset,
|
||||||
|
} from 'firebase/auth';
|
||||||
|
import { FirebaseService } from './firebase.service';
|
||||||
|
import {
|
||||||
|
Firestore,
|
||||||
|
addDoc,
|
||||||
|
collection,
|
||||||
|
doc,
|
||||||
|
getDocs,
|
||||||
|
query,
|
||||||
|
updateDoc,
|
||||||
|
where,
|
||||||
|
} from '@angular/fire/firestore';
|
||||||
|
import { SharedService } from './shared.service';
|
||||||
|
import { User } from '../interfaces/user.interface';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import CryptoES from 'crypto-es';
|
||||||
|
import { CryptoESSecretKey } from '../environments/config';
|
||||||
|
import { catchError, map, Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class LoginService {
|
||||||
|
firestore: Firestore = inject(Firestore);
|
||||||
|
passwordFieldType: string = 'password';
|
||||||
|
passwordIcon: string = './../../../assets/img/login/close-eye.svg';
|
||||||
|
errorCode: string = '';
|
||||||
|
|
||||||
|
private secretKey: string = CryptoESSecretKey.secretKey;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private firebaseService: FirebaseService,
|
||||||
|
public sharedService: SharedService,
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a user is logged in.
|
||||||
|
*
|
||||||
|
* @returns An Observable resolving to a boolean indicating whether a user is logged in.
|
||||||
|
*/
|
||||||
|
checkAuthUser(): Observable<boolean> {
|
||||||
|
return this.firebaseService.getAuthUser().pipe(
|
||||||
|
map((user) => {
|
||||||
|
if (user) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError(() => {
|
||||||
|
return of(false);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs in a user given their email and password.
|
||||||
|
* @param loginData An object with properties `mail` and `password`.
|
||||||
|
* @returns A Promise resolving to void.
|
||||||
|
* @throws An error if the login attempt fails.
|
||||||
|
*/
|
||||||
|
login(loginData: { mail: string; password: string }) {
|
||||||
|
signInWithEmailAndPassword(getAuth(), loginData.mail, loginData.password)
|
||||||
|
.then((userCredential) => {
|
||||||
|
const user = userCredential.user;
|
||||||
|
const userData = this.firebaseService.getUserDataFromUid(user.uid);
|
||||||
|
if (userData.length > 0 && userData[0].id) {
|
||||||
|
this.getUserIdInLocalStorage(userData[0].id);
|
||||||
|
this.updateUserOnlineStatus(userData[0].id, true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.errorCode = error.code;
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new user given their name, first name, last name, email and password.
|
||||||
|
* @param registerData An object with properties `name`, `firstName`, `lastName`, `mail` and `password`.
|
||||||
|
* @returns A Promise resolving to void.
|
||||||
|
* @throws An error if the registration attempt fails.
|
||||||
|
*/
|
||||||
|
register(registerData: {
|
||||||
|
name: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
mail: string;
|
||||||
|
password: string;
|
||||||
|
}) {
|
||||||
|
createUserWithEmailAndPassword(
|
||||||
|
getAuth(),
|
||||||
|
registerData.mail,
|
||||||
|
registerData.password
|
||||||
|
)
|
||||||
|
.then((userCredential) => {
|
||||||
|
const user = userCredential.user;
|
||||||
|
|
||||||
|
const userDataToSave: User = {
|
||||||
|
uId: user.uid,
|
||||||
|
email: user.email || '',
|
||||||
|
firstName: registerData.firstName
|
||||||
|
? registerData.firstName.charAt(0).toUpperCase() +
|
||||||
|
registerData.firstName.slice(1)
|
||||||
|
: '',
|
||||||
|
lastName: registerData.lastName
|
||||||
|
? registerData.lastName.charAt(0).toUpperCase() +
|
||||||
|
registerData.lastName.slice(1)
|
||||||
|
: '',
|
||||||
|
status: true,
|
||||||
|
phone: '',
|
||||||
|
initials: registerData.name
|
||||||
|
? registerData.firstName.slice(0, 1).toUpperCase() +
|
||||||
|
registerData.lastName.slice(0, 1).toUpperCase()
|
||||||
|
: '',
|
||||||
|
color: this.sharedService.generateRandomColor(),
|
||||||
|
lastLogin: new Date().getTime(),
|
||||||
|
};
|
||||||
|
this.createUserInFirestore(userDataToSave);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google login method.
|
||||||
|
*
|
||||||
|
* Signs in the user with Google Authentication.
|
||||||
|
* If the user is not in the database, creates a new user with the provided name and email.
|
||||||
|
* If the user is already in the database, logins the user.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @memberof LoginService
|
||||||
|
*/
|
||||||
|
googleLogin() {
|
||||||
|
const auth = getAuth();
|
||||||
|
const provider = new GoogleAuthProvider();
|
||||||
|
|
||||||
|
signInWithPopup(auth, provider)
|
||||||
|
.then((userCredential) => {
|
||||||
|
const user = userCredential.user;
|
||||||
|
const usersCollection = collection(this.firestore, 'users');
|
||||||
|
const querySnapshot = query(
|
||||||
|
usersCollection,
|
||||||
|
where('uId', '==', user.uid)
|
||||||
|
);
|
||||||
|
getDocs(querySnapshot).then((snapshot) => {
|
||||||
|
if (snapshot.empty) {
|
||||||
|
const displayName = user.displayName || '';
|
||||||
|
const [firstName = '', lastName = ''] = displayName.split(' ');
|
||||||
|
this.createUserInFirestore({
|
||||||
|
uId: user.uid,
|
||||||
|
email: user.email || 'no mail',
|
||||||
|
firstName: firstName.charAt(0).toUpperCase() + firstName.slice(1),
|
||||||
|
lastName: lastName.charAt(0).toUpperCase() + lastName.slice(1),
|
||||||
|
status: true,
|
||||||
|
phone: '',
|
||||||
|
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
||||||
|
color: this.sharedService.generateRandomColor(),
|
||||||
|
lastLogin: 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.ifExistUser(user.uid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user in the Firestore database with the given user data.
|
||||||
|
* If the user already exists in the database, the method does nothing.
|
||||||
|
* @param user The user data to save. The user data should contain the following properties: `uId`, `email`, `firstName`, `lastName`, `initials`, `color`.
|
||||||
|
* @returns A Promise resolving to void.
|
||||||
|
*/
|
||||||
|
async createUserInFirestore(user: User) {
|
||||||
|
const userDataToSave: User = {
|
||||||
|
uId: user.uId,
|
||||||
|
email: user.email,
|
||||||
|
firstName: user.firstName || '',
|
||||||
|
lastName: user.lastName || '',
|
||||||
|
status: true,
|
||||||
|
phone: '',
|
||||||
|
initials: user.initials,
|
||||||
|
color: user.color,
|
||||||
|
lastLogin: new Date().getTime(),
|
||||||
|
};
|
||||||
|
const usersCollection = collection(this.firestore, 'users');
|
||||||
|
try {
|
||||||
|
const docRef = await addDoc(usersCollection, userDataToSave);
|
||||||
|
this.ifExistUser(user.uId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a user with the given user id exists in the database.
|
||||||
|
* If the user exists, the method saves the user's id in the local storage and
|
||||||
|
* updates the user's online status in the database.
|
||||||
|
* @param user The id of the user to check.
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
ifExistUser(user: string) {
|
||||||
|
const userData = this.firebaseService.getUserDataFromUid(user);
|
||||||
|
if (userData.length > 0 && userData[0].id) {
|
||||||
|
this.getUserIdInLocalStorage(userData[0].id);
|
||||||
|
this.updateUserOnlineStatus(userData[0].id, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the online status of the user with the given id in the Firestore database.
|
||||||
|
* If the user's status is set to true, the user's lastLogin property is also updated
|
||||||
|
* to the current time.
|
||||||
|
* @param userId The id of the user to update.
|
||||||
|
* @param status The new online status of the user.
|
||||||
|
* @returns A Promise resolving to void.
|
||||||
|
*/
|
||||||
|
async updateUserOnlineStatus(userId: string, status: boolean) {
|
||||||
|
await updateDoc(doc(collection(this.firestore, 'users'), userId), {
|
||||||
|
status: status,
|
||||||
|
lastLogin: new Date().getTime(),
|
||||||
|
});
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the password field.
|
||||||
|
*
|
||||||
|
* This function switches the input type between 'password' and 'text',
|
||||||
|
* allowing the user to view or hide the password as needed.
|
||||||
|
* It also updates the icon to reflect the current visibility state.
|
||||||
|
*/
|
||||||
|
togglePasswordVisibility() {
|
||||||
|
this.passwordFieldType =
|
||||||
|
this.passwordFieldType === 'password' ? 'text' : 'password';
|
||||||
|
this.toggleIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the password visibility icon.
|
||||||
|
*
|
||||||
|
* This function switches the icon src between the 'close eye' and 'open eye'
|
||||||
|
* icons, indicating whether the password is hidden or visible.
|
||||||
|
*/
|
||||||
|
toggleIcon() {
|
||||||
|
this.passwordIcon =
|
||||||
|
this.passwordIcon === './../../../assets/img/login/close-eye.svg'
|
||||||
|
? './../../../assets/img/login/open-eye.svg'
|
||||||
|
: './../../../assets/img/login/close-eye.svg';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the given userId to local storage, encrypted with the secret key.
|
||||||
|
*
|
||||||
|
* The userId is first stringified and then encrypted with the secret key.
|
||||||
|
* The encrypted string is then saved to local storage under the key
|
||||||
|
* 'currentUserJOIN'. Additionally, the current timestamp is saved to local
|
||||||
|
* storage under the key 'sessionTimeJOIN'.
|
||||||
|
*
|
||||||
|
* @param userId The id of the user to be saved.
|
||||||
|
*/
|
||||||
|
getUserIdInLocalStorage(userId: string): void {
|
||||||
|
const encryptedValue = CryptoES.AES.encrypt(
|
||||||
|
JSON.stringify(userId),
|
||||||
|
this.secretKey
|
||||||
|
).toString();
|
||||||
|
localStorage.setItem('currentUserJOIN', encryptedValue);
|
||||||
|
localStorage.setItem('sessionTimeJOIN', new Date().getTime().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOGOUT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs out the current user by deleting the user ID from local storage and
|
||||||
|
* updating the user's online status to offline in the Firestore database.
|
||||||
|
*
|
||||||
|
* @param userId The id of the user to log out.
|
||||||
|
*/
|
||||||
|
logout(userId: string) {
|
||||||
|
this.deleteUserIdInLocalStorage();
|
||||||
|
this.updateUserOnlineStatus(userId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the user ID from local storage, effectively logging the user out.
|
||||||
|
*
|
||||||
|
* This function removes the user ID from local storage by deleting the
|
||||||
|
* 'currentUserJOIN' and 'sessionTimeJOIN' items.
|
||||||
|
*/
|
||||||
|
deleteUserIdInLocalStorage() {
|
||||||
|
localStorage.removeItem('currentUserJOIN');
|
||||||
|
localStorage.removeItem('sessionTimeJOIN');
|
||||||
|
}
|
||||||
|
|
||||||
|
// FORGOT PASSWORD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates the password reset process for the given email address.
|
||||||
|
*
|
||||||
|
* This function sends a password reset email to the specified email address
|
||||||
|
* using Firebase Authentication. Upon successful sending of the email, the
|
||||||
|
* user is redirected to the password reset notice page. If there is an error,
|
||||||
|
* the button will be re-enabled for the user to try again.
|
||||||
|
*
|
||||||
|
* @param email The email address of the user requesting a password reset.
|
||||||
|
*/
|
||||||
|
passwordReset(email: string) {
|
||||||
|
const auth = getAuth();
|
||||||
|
const actionCodeSettings = {
|
||||||
|
url: 'https://join.andre-kempf.com/',
|
||||||
|
handleCodeInApp: true,
|
||||||
|
};
|
||||||
|
sendPasswordResetEmail(auth, email, actionCodeSettings)
|
||||||
|
.then(() => {
|
||||||
|
this.router.navigate(['/login/notice/pw-send']);
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the user's password given the new password and the oobCode from the
|
||||||
|
* password reset email.
|
||||||
|
*
|
||||||
|
* This function sends a request to Firebase Authentication to reset the user's
|
||||||
|
* password. If the request is successful, it navigates to the password reset
|
||||||
|
* notice page and re-enables the submit button. If there is an error, the
|
||||||
|
* button will be re-enabled for the user to try again.
|
||||||
|
*
|
||||||
|
* @param newPW The new password to be set for the user.
|
||||||
|
* @param oobCode The one-time code from the password reset email.
|
||||||
|
*/
|
||||||
|
newPassword(newPW: string, oobCode: string) {
|
||||||
|
const auth = getAuth();
|
||||||
|
confirmPasswordReset(auth, oobCode, newPW)
|
||||||
|
.then(() => {
|
||||||
|
this.router.navigate(['/login/notice/pw-change']);
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.sharedService.isBtnDisabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,9 @@ import { Router, RouterModule } from '@angular/router';
|
||||||
import { LanguageService } from '../../../../services/language.service';
|
import { LanguageService } from '../../../../services/language.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoginService } from '../../../../services/auth.service';
|
import { LoginService } from '../../../../services/login.service';
|
||||||
import { FirebaseService } from '../../../../services/firebase.service';
|
import { FirebaseService } from '../../../../services/firebase.service';
|
||||||
|
import { AuthService } from '../../../../services/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navbar',
|
selector: 'app-navbar',
|
||||||
|
|
@ -22,6 +23,7 @@ export class NavbarComponent {
|
||||||
constructor(
|
constructor(
|
||||||
public langService: LanguageService,
|
public langService: LanguageService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private authService: AuthService,
|
||||||
private loginService: LoginService,
|
private loginService: LoginService,
|
||||||
private firebaseService: FirebaseService
|
private firebaseService: FirebaseService
|
||||||
) {}
|
) {}
|
||||||
|
|
@ -45,6 +47,6 @@ export class NavbarComponent {
|
||||||
* The user is then navigated to the login page.
|
* The user is then navigated to the login page.
|
||||||
*/
|
*/
|
||||||
logout() {
|
logout() {
|
||||||
this.loginService.logout(this.firebaseService.getCurrentUserId());
|
this.authService.logout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Component, OnInit } from '@angular/core';
|
||||||
import { NavigationEnd, Router, RouterModule } from '@angular/router';
|
import { NavigationEnd, Router, RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LanguageService } from '../../../services/language.service';
|
import { LanguageService } from '../../../services/language.service';
|
||||||
import { LoginService } from '../../../services/auth.service';
|
import { LoginService } from '../../../services/login.service';
|
||||||
import { FirebaseService } from '../../../services/firebase.service';
|
import { FirebaseService } from '../../../services/firebase.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue