diff --git a/src/app/app.component.html b/src/app/app.component.html index 0a08e11..8f9250b 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,6 +1,6 @@ - - + + - + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 4f0fff5..07dcc6b 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -3,8 +3,8 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { HomeNavbarComponent } from './components/home-navbar/home-navbar.component'; import { NavbarComponent } from './components/navbar/navbar.component'; -import { LocalStorageService } from './services/local-storage/local-storage.service'; import { AdminFooterComponent } from './components/admin-footer/admin-footer.component'; +import { AuthService } from './services/auth/auth.service'; @Component({ selector: 'app-root', @@ -14,5 +14,5 @@ import { AdminFooterComponent } from './components/admin-footer/admin-footer.com export class AppComponent { title = 'Memory Map'; - constructor(protected localStorageService: LocalStorageService) {} + constructor(protected authService: AuthService) {} } diff --git a/src/app/auth.guard.ts b/src/app/auth.guard.ts index f3542d0..fd8c903 100644 --- a/src/app/auth.guard.ts +++ b/src/app/auth.guard.ts @@ -1,21 +1,20 @@ import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; -import { LocalStorageService } from './services/local-storage/local-storage.service'; import { ModalService } from './services/modal/modal.service'; +import { AuthService } from './services/auth/auth.service'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate { constructor( - private localStorageService: LocalStorageService, + private authService: AuthService, private router: Router, private loginModalService: ModalService ) {} canActivate(): boolean { - const token = this.localStorageService.getToken(); - if (token) { + if (this.authService.isLoggedIn()) { return true; } else { this.router.navigate(['/']).then(() => { diff --git a/src/app/components/friend-page/friend-page.component.ts b/src/app/components/friend-page/friend-page.component.ts index 31b4daf..638318b 100644 --- a/src/app/components/friend-page/friend-page.component.ts +++ b/src/app/components/friend-page/friend-page.component.ts @@ -3,8 +3,8 @@ import { Component, OnInit } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { debounceTime, distinctUntilChanged, Subject } from 'rxjs'; import { FriendsService } from '../../services/friends/friends.service'; -import { LocalStorageService } from '../../services/local-storage/local-storage.service'; import { UserService } from '../../services/user/user.service'; +import { AuthService } from '../../services/auth/auth.service'; @Component({ selector: 'app-friend-page', @@ -35,7 +35,7 @@ export class FriendPageComponent implements OnInit { constructor( private friendService: FriendsService, private userService: UserService, - private localStorage: LocalStorageService + private authService: AuthService ) {} ngOnInit(): void { @@ -61,7 +61,7 @@ export class FriendPageComponent implements OnInit { } private getUserData(search: string): void { - const username = this.localStorage.getUsername(); + const username = this.authService.getUsername(); this.userService .getUser('^(?!' + username + ')' + search) .subscribe((data: any[]) => { diff --git a/src/app/components/home-page/home-page.component.ts b/src/app/components/home-page/home-page.component.ts index cdc489d..d31d2f5 100644 --- a/src/app/components/home-page/home-page.component.ts +++ b/src/app/components/home-page/home-page.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { ModalService } from '../../services/modal/modal.service'; import { Router } from '@angular/router'; -import { LoginService } from '../../services/login/login.service'; +import { AuthService } from '../../services/auth/auth.service'; @Component({ selector: 'app-home-page', @@ -13,15 +13,14 @@ export class HomePageComponent { constructor( private loginModalService: ModalService, private router: Router, - private loginService: LoginService + private authService: AuthService ) {} openLogin() { - const token = localStorage.getItem('token'); - if (!token) { - this.router.navigate(['/map']); - } else { + if (!this.authService.isLoggedIn()) { this.loginModalService.openModal('login-modal'); + } else { + this.router.navigate(['/map']); } } } diff --git a/src/app/components/login-page/login-page.component.ts b/src/app/components/login-page/login-page.component.ts index 1c69f63..873afcd 100644 --- a/src/app/components/login-page/login-page.component.ts +++ b/src/app/components/login-page/login-page.component.ts @@ -11,8 +11,8 @@ import { Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { User } from '../../model/User'; import { LocalStorageService } from '../../services/local-storage/local-storage.service'; -import { LoginService } from '../../services/login/login.service'; import { ModalService } from '../../services/modal/modal.service'; +import { AuthService } from '../../services/auth/auth.service'; @Component({ selector: 'app-login-page', @@ -28,7 +28,7 @@ export class LoginPageComponent { private modalSub!: Subscription; constructor( - private loginService: LoginService, + private authService: AuthService, private fb: FormBuilder, private router: Router, private modalService: ModalService, @@ -65,11 +65,8 @@ export class LoginPageComponent { this.user.login = this.userForm.value.login; this.user.password = this.userForm.value.password; - this.loginService.login(this.user.login, this.user.password).subscribe({ - next: (response) => { - this.localStorageService.setToken(response.access_token); - this.localStorageService.setUsername(this.user.login); - this.localStorageService.setIsAdmin(response.is_admin); + this.authService.login(this.user.login, this.user.password).subscribe({ + next: () => { this.closeLoginModal(); setTimeout(() => { this.router.navigate(['/map']); diff --git a/src/app/components/navbar/navbar.component.ts b/src/app/components/navbar/navbar.component.ts index 27d2813..19fcb0c 100644 --- a/src/app/components/navbar/navbar.component.ts +++ b/src/app/components/navbar/navbar.component.ts @@ -20,10 +20,10 @@ import { switchMap, } from 'rxjs'; import { Pin } from '../../model/Pin'; -import { LocalStorageService } from '../../services/local-storage/local-storage.service'; import { PinService } from '../../services/pin/pin.service'; import { AddPinPopupComponent } from '../add-pin-popup/add-pin-popup.component'; import { FriendPageComponent } from '../friend-page/friend-page.component'; +import { AuthService } from '../../services/auth/auth.service'; @Component({ selector: 'app-navbar', @@ -61,9 +61,9 @@ export class NavbarComponent implements OnInit { constructor( private router: Router, private route: ActivatedRoute, - private localStorageService: LocalStorageService, private pinService: PinService, - private fb: FormBuilder + private fb: FormBuilder, + private authService: AuthService ) { this.searchForm = this.fb.group({ searchControl: new FormControl(''), @@ -149,9 +149,7 @@ export class NavbarComponent implements OnInit { } public logout() { - this.localStorageService.removeToken(); - this.localStorageService.removeUsername(); - this.localStorageService.removeIsAdmin(); + this.authService.logout(); this.router.navigate(['/']); } } diff --git a/src/app/components/register-page/register-page.component.ts b/src/app/components/register-page/register-page.component.ts index 62de0f0..48d9774 100644 --- a/src/app/components/register-page/register-page.component.ts +++ b/src/app/components/register-page/register-page.component.ts @@ -10,9 +10,8 @@ import { import { Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { User } from '../../model/User'; -import { LocalStorageService } from '../../services/local-storage/local-storage.service'; import { ModalService } from '../../services/modal/modal.service'; -import { RegisterService } from '../../services/register/register.service'; +import { AuthService } from '../../services/auth/auth.service'; @Component({ selector: 'app-register-page', @@ -28,9 +27,8 @@ export class RegisterPageComponent { private modalSub!: Subscription; constructor( - private registerService: RegisterService, + private authService: AuthService, private fb: FormBuilder, - private localStorageService: LocalStorageService, private modalService: ModalService, private router: Router ) { @@ -79,12 +77,12 @@ export class RegisterPageComponent { this.user.login = this.userForm.value.login; this.user.password = this.userForm.value.password; - this.registerService + this.authService .register(this.user.login, this.user.password) .subscribe({ - next: (response) => { - this.localStorageService.setToken(response.access_token); + next: () => { this.closeRegisterModal(); + setTimeout(() => { this.router.navigate(['/map']); }, 1); diff --git a/src/app/model/AuthResponse.ts b/src/app/model/AuthResponse.ts new file mode 100644 index 0000000..77cad02 --- /dev/null +++ b/src/app/model/AuthResponse.ts @@ -0,0 +1,6 @@ +export interface AuthResponse { + access_token: string; + token_type: string; + user_id: string; + is_admin: boolean; +} \ No newline at end of file diff --git a/src/app/services/login/login.service.spec.ts b/src/app/services/auth/auth.service.spec.ts similarity index 56% rename from src/app/services/login/login.service.spec.ts rename to src/app/services/auth/auth.service.spec.ts index 299b0d5..f1251ca 100644 --- a/src/app/services/login/login.service.spec.ts +++ b/src/app/services/auth/auth.service.spec.ts @@ -1,13 +1,13 @@ import { TestBed } from '@angular/core/testing'; -import { LoginService } from './login.service'; +import { AuthService } from './auth.service'; -describe('LoginService', () => { - let service: LoginService; +describe('AuthService', () => { + let service: AuthService; beforeEach(() => { TestBed.configureTestingModule({}); - service = TestBed.inject(LoginService); + service = TestBed.inject(AuthService); }); it('should be created', () => { diff --git a/src/app/services/auth/auth.service.ts b/src/app/services/auth/auth.service.ts new file mode 100644 index 0000000..63d1110 --- /dev/null +++ b/src/app/services/auth/auth.service.ts @@ -0,0 +1,80 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { BehaviorSubject, Observable, tap } from 'rxjs'; +import { environment } from '../../../environment'; +import { LocalStorageService } from '../local-storage/local-storage.service'; +import { AuthResponse } from '../../model/AuthResponse'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + private isAdminSubject = new BehaviorSubject(false); + isAdmin$ = this.isAdminSubject.asObservable(); + username$ = new BehaviorSubject(''); + isLoggedIn$ = new BehaviorSubject(false); + + constructor(private http: HttpClient, private localStorageService: LocalStorageService) { + const token = this.localStorageService.getToken(); + if (token) { + this.isAdminSubject.next(this.localStorageService.getIsAdmin() === 'true'); + this.username$.next(this.localStorageService.getUsername() || ''); + this.isLoggedIn$.next(true); + } + } + + login(username: string, password: string): Observable { + const payload = new HttpParams() + .set('username', username) + .set('password', password); + + return this.http.post(`${environment.apiURL}/login`, payload).pipe( + tap(response => { + this.localStorageService.setToken(response.access_token); + this.localStorageService.setIsAdmin(response.is_admin); + this.localStorageService.setUsername(username); + this.isAdminSubject.next(response.is_admin); + this.username$.next(username); + this.isLoggedIn$.next(true); + }) + ); + } + + logout(): void { + this.localStorageService.removeToken(); + this.localStorageService.removeIsAdmin(); + this.isAdminSubject.next(false); + this.username$.next(''); + this.isLoggedIn$.next(false); + } + + register(username: string, password: string): Observable { + return this.http.post(`${environment.apiURL}/register`, { username, password }).pipe( + tap(response => { + this.localStorageService.setToken(response.access_token); + this.localStorageService.setIsAdmin(response.is_admin); + this.localStorageService.setUsername(username); + this.isAdminSubject.next(response.is_admin); + this.username$.next(username); + this.isLoggedIn$.next(true); + }) + ); + } + + isAdmin(): boolean { + return this.isAdminSubject.value || false; + } + + getAuthHeaders(): HttpHeaders { + const token = this.localStorageService.getToken(); + return new HttpHeaders().set('Authorization', `Bearer ${token}`); + } + + getUsername(): string { + return this.username$.value || ''; + } + + isLoggedIn(): boolean { + return this.isLoggedIn$.value || false; + } +} \ No newline at end of file diff --git a/src/app/services/friends/friends.service.ts b/src/app/services/friends/friends.service.ts index 79ce2a1..527fd82 100644 --- a/src/app/services/friends/friends.service.ts +++ b/src/app/services/friends/friends.service.ts @@ -1,65 +1,60 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from '../../../environment'; +import { AuthService } from '../auth/auth.service'; @Injectable({ providedIn: 'root', }) export class FriendsService { private apiURL = environment.apiURL; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient, private authService: AuthService) {} getFriend() { const url = `${this.apiURL}/friends`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.get(url, { headers }); } getFriendById(id: string) { const url = `${this.apiURL}/user/${id}`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.get(url, { headers }); } addFriend(user_id: string) { const url = `${this.apiURL}/friend/add`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.post(url, { friend_user_id: user_id }, { headers }); } acceptFriendById(id: string) { const url = `${this.apiURL}/friend/${id}/accept`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.patch(url, [], { headers }); } denyFriendById(id: string) { const url = `${this.apiURL}/friend/${id}/deny`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.delete(url, { headers }); } deleteFriend(id: string) { const url = `${this.apiURL}/friend/${id}/delete`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.delete(url, { headers }); } } diff --git a/src/app/services/image/image.service.ts b/src/app/services/image/image.service.ts index b7790c8..81e8161 100644 --- a/src/app/services/image/image.service.ts +++ b/src/app/services/image/image.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { environment } from '../../../environment'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { LocalStorageService } from '../local-storage/local-storage.service'; +import { AuthService } from '../auth/auth.service'; @Injectable({ providedIn: 'root' @@ -12,14 +12,11 @@ export class ImageService { constructor( private http: HttpClient, - private localStorageService: LocalStorageService + private authService: AuthService ) { } getImage(imageId: string): Observable { - const token = this.localStorageService.getToken(); - const headers = new HttpHeaders({ - 'Authorization': `Bearer ${token}` - }); + const headers = this.authService.getAuthHeaders(); return this.http.get(`${this.apiUrl}/image/${imageId}`, { headers, @@ -28,10 +25,7 @@ export class ImageService { } postImage(image: File): Observable { - const token = this.localStorageService.getToken(); - const headers = new HttpHeaders({ - 'Authorization': `Bearer ${token}` - }); + const headers = this.authService.getAuthHeaders(); const formData = new FormData(); formData.append('image', image); @@ -40,10 +34,7 @@ export class ImageService { } getImageMetadata(imageId: string): Observable { - const token = this.localStorageService.getToken(); - const headers = new HttpHeaders({ - 'Authorization': `Bearer ${token}` - }); + const headers = this.authService.getAuthHeaders(); return this.http.get(`${this.apiUrl}/image/${imageId}/metadata`, { headers }); } diff --git a/src/app/services/login/login.service.ts b/src/app/services/login/login.service.ts deleted file mode 100644 index 1bf894c..0000000 --- a/src/app/services/login/login.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from '../../../environment'; - -@Injectable({ - providedIn: 'root', -}) -export class LoginService { - private apiUrl = environment.apiURL; - - constructor(private http: HttpClient) {} - - login(username: string, password: string): Observable { - const payload = new HttpParams() - .set('username', username) - .set('password', password); - - return this.http.post(this.apiUrl + '/login', payload); - } -} diff --git a/src/app/services/pin/pin.service.ts b/src/app/services/pin/pin.service.ts index 0d57b16..d764e70 100644 --- a/src/app/services/pin/pin.service.ts +++ b/src/app/services/pin/pin.service.ts @@ -4,6 +4,7 @@ import { switchMap } from 'rxjs'; import { environment } from '../../../environment'; import { Pin } from '../../model/Pin'; import { AutocompleteService } from '../auto-complete/auto-complete.service'; +import { AuthService } from '../auth/auth.service'; // import { ImageService } from '../image/image.service'; @Injectable({ @@ -17,24 +18,23 @@ export class PinService { constructor( private http: HttpClient, - private autoCompleteService: AutocompleteService // private imageService: ImageService + private autoCompleteService: AutocompleteService, + private authService: AuthService ) {} getPins(): any { const url = `${this.apiURL}/pins`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.get(url, { headers }); } addPin(pin: Pin) { const url = `${this.apiURL}/pin/add`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.post( url, pin, { headers } ); @@ -45,10 +45,9 @@ export class PinService { pin: Pin ) { const url = `${this.apiURL}/pin/${id}`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + // Obtenir les coordonnées GPS à partir de l'adresse return this.http.patch( @@ -58,19 +57,17 @@ export class PinService { deletePin(id: string) { const url = `${this.apiURL}/pin/${id}`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.delete(url, { headers }); } sharePin(pinId: string, friendId: string) { const url = `${this.apiURL}/pin/${pinId}/share`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + return this.http.post(url, { friend_id: friendId }, { headers }); } } diff --git a/src/app/services/register/register.service.spec.ts b/src/app/services/register/register.service.spec.ts deleted file mode 100644 index 2ba3960..0000000 --- a/src/app/services/register/register.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { RegisterService } from './register.service'; - -describe('RegisterService', () => { - let service: RegisterService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(RegisterService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/services/register/register.service.ts b/src/app/services/register/register.service.ts deleted file mode 100644 index 9940f76..0000000 --- a/src/app/services/register/register.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from '../../../environment'; - -@Injectable({ - providedIn: 'root', -}) -export class RegisterService { - private apiUrl = environment.apiURL; - - constructor(private http: HttpClient) {} - - register(username: string, password: string): Observable { - return this.http.post(this.apiUrl + '/register', { username, password }); - } -} diff --git a/src/app/services/user/user.service.ts b/src/app/services/user/user.service.ts index a52e5e3..936753a 100644 --- a/src/app/services/user/user.service.ts +++ b/src/app/services/user/user.service.ts @@ -1,6 +1,7 @@ import { Injectable, OnInit } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { environment } from '../../../environment'; +import { AuthService } from '../auth/auth.service'; @Injectable({ providedIn: 'root' @@ -8,15 +9,14 @@ import { environment } from '../../../environment'; export class UserService { private apiURL = environment.apiURL; - constructor(private http: HttpClient) { + constructor(private http: HttpClient, private authService: AuthService) { } getUser(username:string) { const url = `${this.apiURL}/users`; - const headers = new HttpHeaders({ - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + localStorage.getItem('auth_token'), - }); + const headers = this.authService.getAuthHeaders(); + headers.set('Content-Type', 'application/json'); + const params = { name : username }; return this.http.get(url,{ headers:headers, params:params })