Intégration de l'appel a l'api auth dans les méthodes login et register. Formgroup utilisé pour la page register, mais pas encore pour le login

This commit is contained in:
mjeannin2025 2025-10-31 12:55:48 +01:00
parent 5dda6c87fe
commit 12c8d422a5
9 changed files with 165 additions and 99 deletions

View File

@ -0,0 +1,5 @@
export interface ApiResponse<T> {
code: string,
message: string,
data: T
}

View File

@ -4,9 +4,19 @@ export interface User {
roles: string[] roles: string[]
} }
//TODO: Passer a une gestion par roles et non par un booléen isAdmin
export interface LoggedUser { export interface LoggedUser {
email: string, email: string,
token: string, token: string,
roles: string[] roles: string[]
} }
export interface UserToRegister {
email: string,
pseudo: string,
password: string,
passwordConfirm: string,
cityCode: string,
city: string,
phone: string,
}

View File

@ -1,5 +1,6 @@
import { Component, inject, signal, Signal } from '@angular/core'; import { Component, inject, signal, Signal } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { firstValueFrom } from 'rxjs';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -22,15 +23,21 @@ export class Login {
constructor(private readonly userService: Auth, private readonly router: Router){ constructor(private readonly userService: Auth, private readonly router: Router){
} }
login() { async login() {
const userToConnect : User = {email: this.email(), password: this.password(),roles: []} const userToConnect : User = {email: this.email(), password: this.password(),roles: []}
const loginSuccess = this.userService.login(userToConnect) try{
const loginSuccess =await firstValueFrom(this.userService.login(userToConnect));
if(loginSuccess){ if(loginSuccess){
this.router.navigate(['/profile']); this.router.navigate(['/profile']);
} }
else { else {
this.errorMessage.set('Email ou mot de passe incorrect'); this.errorMessage.set('Email ou mot de passe incorrect');
} }
}catch (error) {
console.error('Erreur lors du login:', error);
this.errorMessage.set('Une erreur est survenue. Veuillez réessayer.');
}
} }
updateEmail(event: Event) { updateEmail(event: Event) {

View File

@ -1,18 +1,33 @@
<!-- TODO: utiliser des formgroup -->
<div class = "form-container"> <div class = "form-container">
<form (ngSubmit)="OnSubmit()"> <form [formGroup]="registerForm" (ngSubmit)="OnSubmit()">
<fieldset > <fieldset >
<legend >Register</legend> <legend >Register</legend>
<div> <div>
<input class="input" type="text" [value]="email()" (input)="updateEmail($event)" placeholder="Mail" aria-label="email"> <input class="input" type="text" formControlName="email" placeholder="Mail" aria-label="email">
</div> </div>
<div> <div>
<input class="input" type="text" [value]="password()" (input)="updatePassword($event)" placeholder="Password" aria-label="password"> <input class="input" type="text" formControlName="pseudo" placeholder="pseudo" aria-label="username">
</div> </div>
<div> <div>
<input class="input" type="text" [value]="passwordConfirm()" (input)="updateConfirmPassword($event)" placeholder="confirm Password" aria-label="password"> <input class="input" type="text" formControlName="password" placeholder="Password" aria-label="password">
</div>
<div>
<input class="input" type="text" formControlName="passwordConfirm" placeholder="confirm Password" aria-label="password">
</div>
<div>
<input class="input" type="text" formControlName="cityCode" placeholder="cityCode" aria-label="cityCode">
</div>
<div>
<input class="input" type="text" formControlName="city" placeholder="city" aria-label="city">
</div>
<div>
<input class="input" type="text" formControlName="phone" placeholder="phone" aria-label="phone">
</div> </div>
</fieldset> </fieldset>
<!-- Affichage des erreurs -->
@if (errorMessage()) {
<p class="error">{{ errorMessage() }}</p>
}
<button class="btn" type="submit">register</button> <button class="btn" type="submit">register</button>
</form> </form>
</div> </div>

View File

@ -1,52 +1,58 @@
import { Component, inject, Signal, signal } from '@angular/core'; import { Component, inject, Signal, signal } from '@angular/core';
import { User } from '../../interfaces/user'; import { User, UserToRegister } from '../../interfaces/user';
import { FormsModule } from '@angular/forms'; import { FormGroup, FormBuilder, Validator, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router, RouterLink } from '@angular/router'; import { Router, RouterLink } from '@angular/router';
import { Auth } from '../../services/auth'; import { Auth } from '../../services/auth';
import { firstValueFrom } from 'rxjs';
@Component({ @Component({
selector: 'app-register', selector: 'app-register',
imports: [FormsModule], imports: [ReactiveFormsModule],
templateUrl: './register.html', templateUrl: './register.html',
styleUrl: './register.css', styleUrl: './register.css',
}) })
export class Register { export class Register {
email = signal(''); registerForm: FormGroup;
password = signal('');
passwordConfirm = signal('');
errorMessage = signal(''); errorMessage = signal('');
constructor(private readonly userService: Auth, constructor(
private readonly router: Router) { private readonly userService: Auth,
private readonly router: Router,
private fb: FormBuilder) {
this.registerForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
pseudo:['', [Validators.required, Validators.minLength(2)]],
password: ['', [Validators.required, Validators.minLength(2)]],
passwordConfirm: ['', Validators.required],
cityCode: ['', Validators.required],
city:['',Validators.required],
phone: ['',Validators.required]
});
} }
OnSubmit() { async OnSubmit() {
if (this.password() == this.passwordConfirm()) { if (this.registerForm.invalid) {
console.log(this.email()); this.errorMessage.set('Veuillez remplir tous les champs correctement.');
const userToRegister: User = {email: this.email(), password: this.password(), roles: ['ADMIN']} return;
const register = this.userService.register(userToRegister) }
if(register){ const user: UserToRegister = this.registerForm.value;
this.router.navigate(["/login"]) //appel au service register
try{
const registerSuccess: boolean = await firstValueFrom(this.userService.register(user))
if(registerSuccess){
this.router.navigate(['/login']);
} }
else{ else{
this.errorMessage.set('Email ou mot de passe incorrect'); this.errorMessage.set('Une erreur est survenue');
}
} }
}catch(error){
console.error('Erreur lors de l\'inscription:', error);
this.errorMessage.set('Une erreur est survenue. Veuillez réessayer.');
};
} }
updateEmail(event: Event) {
const target = event.target as HTMLInputElement;
this.email.set(target.value);
}
updatePassword(event: Event) {
const target = event.target as HTMLInputElement;
this.password.set(target.value);
}
updateConfirmPassword(event: Event) {
const target = event.target as HTMLInputElement;
this.passwordConfirm.set(target.value);
}
} }

View File

@ -11,8 +11,8 @@ import { Router } from '@angular/router';
styleUrl: './search.css' styleUrl: './search.css'
}) })
export class Search { export class Search {
private nasaApi = inject(NAPOD); private readonly nasaApi = inject(NAPOD);
private router = inject(Router) private readonly router = inject(Router)
searchResults = signal<NasaApi | null>(null) searchResults = signal<NasaApi | null>(null)
searchString=signal(''); searchString=signal('');

View File

@ -3,6 +3,8 @@ import { ActivatedRoute } from '@angular/router';
import { Collection } from '../../interfaces/nasa-api'; import { Collection } from '../../interfaces/nasa-api';
import { NAPOD } from '../../services/napod'; import { NAPOD } from '../../services/napod';
@Component({ @Component({
selector: 'app-video', selector: 'app-video',
imports: [], imports: [],
@ -10,21 +12,19 @@ import { NAPOD } from '../../services/napod';
styleUrl: './video.css' styleUrl: './video.css'
}) })
export class Video { export class Video {
private route = inject(ActivatedRoute) private readonly route = inject(ActivatedRoute)
asset=signal<Collection|null>(null); asset=signal<Collection|null>(null);
//TODO: nom de merde pour le service a changer //TODO: nom nul pour le service a changer
private nasaApi: NAPOD = inject(NAPOD) private readonly nasaApi: NAPOD = inject(NAPOD)
isLoading = signal<boolean>(true); isLoading = signal<boolean>(true);
ngOnInit(){ ngOnInit(){
const nasaId=this.route.snapshot.params['id']; const nasaId=this.route.snapshot.params['id'];
this.nasaApi.getAssetDetail(nasaId).subscribe({ this.nasaApi.getAssetDetail(nasaId).subscribe({
next: (data)=>{ next: (data)=>{
this.asset.set(data.collection); this.asset.set(data.collection);
this.isLoading.set(false); this.isLoading.set(false);
console.log(this.asset()); console.log(this.asset());
}, },
error: error =>{ error: error =>{
console.log(error); console.log(error);

View File

@ -1,12 +1,17 @@
import { Injectable, signal } from '@angular/core'; import { inject, Injectable, signal } from '@angular/core';
import { LoggedUser, User } from '../interfaces/user'; import { LoggedUser, User, UserToRegister } from '../interfaces/user';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { environment } from '../../environments/environment.development';
import { ApiResponse } from '../interfaces/apiResponse';
import { catchError, map, Observable, of } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class Auth { export class Auth {
private connectedUserSignal = signal<LoggedUser|null>(null); private readonly connectedUserSignal = signal<LoggedUser|null>(null);
private users = signal<User[]>([]); private readonly users = signal<User[]>([]);
private readonly http = inject(HttpClient);
constructor(){ constructor(){
this.loadStoredData(); this.loadStoredData();
@ -36,51 +41,69 @@ export class Auth {
return this.users().find(user=>user.email==userEmail)!; return this.users().find(user=>user.email==userEmail)!;
} }
register(user: User): boolean{ register(user: UserToRegister): Observable<boolean>{
console.log("time to save users"); const apiUrl = `${environment.AUTH_API_BASE}/signup`;
const requestBody = {
email: user.email,
pseudo: user.pseudo,
password: user.password,
passwordConfirm: user.passwordConfirm,
cityCode: user.cityCode,
city: user.city,
phone: user.phone };
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
if(this.users().find(u => u.email===user.email)){ return this.http.post<ApiResponse<LoggedUser>>(apiUrl, requestBody, { headers }).pipe(
console.log("seem to be such a user already"+user.email); map((res)=>{
if(res.code==="200"){
return false;
}
this.users.update(users=>[...users,user])
this.saveUsers();
return true;
}
saveUsers() {
localStorage.setItem('users', JSON.stringify(this.users()))
}
//################################ LOGIN/LOGOUT ###############################
login(userToConnect: User): boolean {
const userToCheck = this.getUserByEmail(userToConnect.email);
console.log("User has been found : " + userToCheck.email);
if(!userToCheck){
console.log("No such user");
return false;
}
else if(userToCheck.password==userToConnect.password){
console.log("password is ok");
//ATTENTION: ici il faut stocker le isAdmin de userToCheck parce que
// l'information sur le role est récupérée lors du getUser
const userStoreData: LoggedUser = { email: userToConnect.email,
token: 'fake-jwt'+Date.now(), roles: userToCheck.roles
}
sessionStorage.setItem('connectedUser',JSON.stringify(userStoreData))
this.connectedUserSignal.set(userStoreData);
return true; return true;
} }
else { else {
console.log("password doesn't seem right"); console.error('Erreur lors du register:');
return false return false;
} }
} }
)
)
}
//################################ LOGIN/LOGOUT ###############################
login(userToConnect: User): Observable<boolean> {
const apiUrl = `${environment.AUTH_API_BASE}/login`;
const requestBody = { email: userToConnect.email, password: userToConnect.password };
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
return this.http.post<ApiResponse<LoggedUser>>(apiUrl, requestBody, { headers }).pipe(
map((res) => {
if (res.code === '200') {
const userStoreData: LoggedUser = {
email: res.data.email,
token: res.data.token,
roles: res.data.roles || []
};
sessionStorage.setItem('connectedUser', JSON.stringify(userStoreData));
this.connectedUserSignal.set(userStoreData);
return true;
} else {
console.log("Mot de passe ou email incorrect");
return false;
}
}),
catchError((error) => {
console.error('Erreur lors du login:', error);
return of(false);
})
);
}
logout(){ logout(){
sessionStorage.removeItem('connectedUser'); sessionStorage.removeItem('connectedUser');

View File

@ -1,7 +1,7 @@
export const environment = { export const environment = {
production: false, production: false,
BASE_COLOR_API_URL: 'https://www.colourlovers.com/api/',
NASA_API_BASE_URL : "https://api.nasa.gov", NASA_API_BASE_URL : "https://api.nasa.gov",
NASA_API_KEY: '3azuPabFKF5HNbHpZuQ1rGzIPO6i2DbOLQ6hYuGl', NASA_API_KEY: '3azuPabFKF5HNbHpZuQ1rGzIPO6i2DbOLQ6hYuGl',
NASA_API_IMAGE_BASE_URL:'https://images-api.nasa.gov' NASA_API_IMAGE_BASE_URL:'https://images-api.nasa.gov',
AUTH_API_BASE:'http://makusu.duckdns.org:3000'
}; };