diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index cc9f16a2572084418e8084ac0e8436e89d5fe78e..e7e52edb3be6d27dd87c88827df1c825b5ba2df8 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,8 +1,10 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AboutComponent } from './about/about.component'; +import { AuthGuard } from './guards/auth.guard'; import { HomeComponent } from './home/home.component'; import { LegalNoticeComponent } from './legal-notice/legal-notice.component'; +import { ProfileComponent } from './profile/profile.component'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureListComponent } from './structure-list/structure-list.component'; import { UserVerificationComponent } from './user-verification/user-verification.component'; @@ -41,6 +43,11 @@ const routes: Routes = [ path: 'users/verify/:id', component: UserVerificationComponent, }, + { + path: 'profile', + canActivate: [AuthGuard], + component: ProfileComponent, + }, { path: '**', redirectTo: 'home', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 02649bb0928321b50390bc3aee7092d6fcdc9ef5..c5162db74ea18d136e90a672bc6640d46a2258ef 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,5 +1,5 @@ import { LOCALE_ID, NgModule } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { BrowserModule } from '@angular/platform-browser'; import { FlexLayoutModule } from '@angular/flex-layout'; @@ -23,6 +23,9 @@ import { LegalNoticeComponent } from './legal-notice/legal-notice.component'; import { AboutComponent } from './about/about.component'; import { MenuPhoneComponent } from './menu-phone/menu-phone.component'; import { UserVerificationComponent } from './user-verification/user-verification.component'; +import { AuthGuard } from './guards/auth.guard'; +import { CustomHttpInterceptor } from './config/http-interceptor'; +import { ProfileModule } from './profile/profile.module'; @NgModule({ declarations: [ @@ -50,8 +53,14 @@ import { UserVerificationComponent } from './user-verification/user-verification MapModule, FormsModule, ReactiveFormsModule, + ProfileModule, + ], + providers: [ + { provide: LOCALE_ID, useValue: 'fr' }, + { provide: HTTP_INTERCEPTORS, useClass: CustomHttpInterceptor, multi: true }, + CustomBreakPointsProvider, + AuthGuard, ], - providers: [{ provide: LOCALE_ID, useValue: 'fr' }, CustomBreakPointsProvider], bootstrap: [AppComponent], }) export class AppModule {} diff --git a/src/app/config/http-interceptor.ts b/src/app/config/http-interceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..caa70fa29ad5a660413cb43def77a1989285c655 --- /dev/null +++ b/src/app/config/http-interceptor.ts @@ -0,0 +1,34 @@ +import { Observable } from 'rxjs'; +import { Injectable } from '@angular/core'; +import { HttpInterceptor } from '@angular/common/http'; +import { HttpRequest } from '@angular/common/http'; +import { HttpHandler } from '@angular/common/http'; +import { HttpEvent } from '@angular/common/http'; +import { HttpHeaders } from '@angular/common/http'; +import { AuthService } from '../services/auth.service'; + +@Injectable() +export class CustomHttpInterceptor implements HttpInterceptor { + constructor(private authService: AuthService) {} + + intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { + const token = this.authService.token; + let changedRequest = request; + // HttpHeader object immutable - copy values + const headerSettings: { [name: string]: string | string[] } = {}; + + for (const key of request.headers.keys()) { + headerSettings[key] = request.headers.getAll(key); + } + if (token) { + headerSettings['Authorization'] = 'Bearer ' + token; + } + headerSettings['Content-Type'] = 'application/json'; + const newHeader = new HttpHeaders(headerSettings); + + changedRequest = request.clone({ + headers: newHeader, + }); + return next.handle(changedRequest); + } +} diff --git a/src/app/guards/auth.guard.ts b/src/app/guards/auth.guard.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d3205c2e848f41f2425f3a04bb931ce66c15a63 --- /dev/null +++ b/src/app/guards/auth.guard.ts @@ -0,0 +1,19 @@ +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { Injectable } from '@angular/core'; +import { AuthService } from '../services/auth.service'; +import { Observable } from 'rxjs'; + +/** + * Guard to assert that we are logged in. Otherwise redirect to home + */ +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private authService: AuthService, private router: Router) {} + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree | boolean { + if (this.authService.isLoggedIn()) { + return true; + } + return this.router.parseUrl('/home'); + } +} diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index f933d061ed0f48e2f2dee5818a41825b88a6139a..863bf211bce5dccdacfba72fcbbb94a3de555c56 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -14,12 +14,15 @@ <a routerLink="/projects" [routerLinkActive]="'active'" i18n>Projets</a> --> <a routerLink="/about" [routerLinkActive]="'active'" i18n>Qui sommes-nous ?</a> <!-- <a routerLink="/login" [routerLinkActive]="'active'" i18n><span class="clickable ico-mglass purple"></span></a> --> - <button *ngIf="!isLoggedIn" (click)="isPopUpOpen = !isPopUpOpen"> + <a *ngIf="!isLoggedIn" (click)="isPopUpOpen = !isPopUpOpen"> <span class="ico-profile" fxLayout="column" fxLayoutAlign="center center"> <span class="head"></span> <span class="body"></span> </span> - </button> + </a> + <a *ngIf="isLoggedIn" routerLink="/profile" [routerLinkActive]="'active'" fxLayout="row" fxLayoutGap="1.5vh"> + <app-svg-icon [type]="'ico'" [iconClass]="'icon-32'" [icon]="'user'" [iconColor]="'currentColor'"></app-svg-icon> + </a> <button *ngIf="isLoggedIn" (click)="logout()">Logout</button> </div> </div> diff --git a/src/app/map/map.module.ts b/src/app/map/map.module.ts index 3487eb49d47035b00a1bd66a07ac50c5feb7fdfa..521ecc6784cc5b12659516889e1526cf69bcb5df 100644 --- a/src/app/map/map.module.ts +++ b/src/app/map/map.module.ts @@ -4,8 +4,9 @@ import { SharedModule } from '../shared/shared.module'; import { MapComponents } from './components'; import { LeafletModule } from '@asymmetrik/ngx-leaflet'; import { NgxLeafletLocateModule } from '@runette/ngx-leaflet-locate'; +import { BrowserModule } from '@angular/platform-browser'; @NgModule({ - imports: [CommonModule, SharedModule, NgxLeafletLocateModule, LeafletModule], + imports: [CommonModule, BrowserModule, SharedModule, NgxLeafletLocateModule, LeafletModule], declarations: [MapComponents], providers: [DatePipe], exports: [MapComponents], diff --git a/src/app/models/user.model.ts b/src/app/models/user.model.ts index 3269aeea7176afe91ee0e1eab134afc46aae0762..aa2391853d058ee08bd800715ec4bd620220678b 100644 --- a/src/app/models/user.model.ts +++ b/src/app/models/user.model.ts @@ -1,7 +1,7 @@ export class User { _id: string; email: string; - password: string; + password?: string; emailVerified: boolean; role: number; validationToken: string; diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ac9939990b5e965f301f3472db7dd3f3068b51ce --- /dev/null +++ b/src/app/profile/profile.component.html @@ -0,0 +1,9 @@ +<div fxLayout="column" class="content-container"> + <div class="section-container" fxLayout="colum" fxLayoutAlign="center center"> + <h1>Profil</h1> + <div *ngIf="userProfile" fxLayout="column" fxLayoutAlign="center" fxLayoutGap="10px"> + <p>Id: {{ userProfile._id }}</p> + <p>Email: {{ userProfile.email }}</p> + </div> + </div> +</div> diff --git a/src/app/profile/profile.component.scss b/src/app/profile/profile.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/profile/profile.component.spec.ts b/src/app/profile/profile.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e88012e7aeab34312f88c177994686deb064e20b --- /dev/null +++ b/src/app/profile/profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProfileComponent } from './profile.component'; + +describe('ProfileComponent', () => { + let component: ProfileComponent; + let fixture: ComponentFixture<ProfileComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..04a353c04221759d2ee7e083420304aea462014a --- /dev/null +++ b/src/app/profile/profile.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit } from '@angular/core'; +import { User } from '../models/user.model'; +import { ProfileService } from './services/profile.service'; + +@Component({ + selector: 'app-profile', + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.scss'], +}) +export class ProfileComponent implements OnInit { + public userProfile: User; + + constructor(private profileService: ProfileService) {} + + ngOnInit(): void { + this.profileService.getProfile().subscribe((profile) => { + this.userProfile = profile; + }); + } +} diff --git a/src/app/profile/profile.module.ts b/src/app/profile/profile.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9427003f2507d4092e966617363aa223996b4f5 --- /dev/null +++ b/src/app/profile/profile.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { ProfileComponent } from './profile.component'; +import { SharedModule } from '../shared/shared.module'; +import { CommonModule } from '@angular/common'; +import { BrowserModule } from '@angular/platform-browser'; + +@NgModule({ + imports: [CommonModule, BrowserModule, SharedModule], + declarations: [ProfileComponent], + exports: [ProfileComponent], +}) +export class ProfileModule {} diff --git a/src/app/profile/services/profile.service.ts b/src/app/profile/services/profile.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e43c87840e4ee4081a7df112b62ccd64b3910ac --- /dev/null +++ b/src/app/profile/services/profile.service.ts @@ -0,0 +1,15 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { User } from '../../models/user.model'; + +@Injectable({ + providedIn: 'root', +}) +export class ProfileService { + constructor(private http: HttpClient) {} + + public getProfile(): Observable<User> { + return this.http.get<User>('api/users/profile'); + } +}