diff --git a/package-lock.json b/package-lock.json
index f966c1c..e4024bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,7 @@
"@angular/ssr": "^18.2.12",
"express": "^4.18.2",
"luxon": "^3.5.0",
+ "ngx-cookie-service": "^18.0.0",
"primeicons": "^7.0.0",
"primeng": "^17.18.10",
"rxjs": "~7.8.0",
@@ -32,6 +33,7 @@
"@angular/compiler-cli": "^18.2.0",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
+ "@types/jwt-decode": "^3.1.0",
"@types/node": "^18.18.0",
"jasmine-core": "~5.2.0",
"karma": "~6.4.0",
@@ -4462,6 +4464,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/jwt-decode": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz",
+ "integrity": "sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w==",
+ "deprecated": "This is a stub types definition. jwt-decode provides its own type definitions, so you do not need this installed.",
+ "dev": true,
+ "dependencies": {
+ "jwt-decode": "*"
+ }
+ },
"node_modules/@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@@ -8479,6 +8491,15 @@
],
"license": "MIT"
},
+ "node_modules/jwt-decode": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
+ "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/karma": {
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz",
@@ -9798,6 +9819,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/ngx-cookie-service": {
+ "version": "18.0.0",
+ "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-18.0.0.tgz",
+ "integrity": "sha512-hkkUckzZTXXWtFgvVkT2hg6mwYMLXioXDZWBsVCOy9gYkADjsj0N5VViO7eo2izQ0VcMPd/Etog1trf/T4oZMQ==",
+ "dependencies": {
+ "tslib": "^2.6.2"
+ },
+ "peerDependencies": {
+ "@angular/common": "^18.0.0-rc.0",
+ "@angular/core": "^18.0.0-rc.0"
+ }
+ },
"node_modules/nice-napi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
diff --git a/package.json b/package.json
index f8e8e2f..f110e8d 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@angular/ssr": "^18.2.12",
"express": "^4.18.2",
"luxon": "^3.5.0",
+ "ngx-cookie-service": "^18.0.0",
"primeicons": "^7.0.0",
"primeng": "^17.18.10",
"rxjs": "~7.8.0",
@@ -35,6 +36,7 @@
"@angular/compiler-cli": "^18.2.0",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
+ "@types/jwt-decode": "^3.1.0",
"@types/node": "^18.18.0",
"jasmine-core": "~5.2.0",
"karma": "~6.4.0",
diff --git a/src/app/app.component.css b/src/app/app.component.css
index 7f98bd0..e69de29 100644
--- a/src/app/app.component.css
+++ b/src/app/app.component.css
@@ -1,5 +0,0 @@
-img {
- width: 100%;
- height: 25rem;
- object-fit: cover;
-}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 3138661..0680b43 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,3 +1 @@
-
-
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 163ddcb..d6c93ed 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,7 +1,8 @@
-import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {Component} from '@angular/core';
import {MenubarModule} from 'primeng/menubar';
import {MenuItem} from 'primeng/api';
import {FloatLabelModule} from 'primeng/floatlabel';
+import {CookieService} from 'ngx-cookie-service';
@Component({
selector: 'app-root',
@@ -10,21 +11,9 @@ import {FloatLabelModule} from 'primeng/floatlabel';
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
-export class AppComponent {
- items: MenuItem[] | undefined
+export class AppComponent{
+ items: MenuItem[] = []
- constructor() {
- this.items = [
- {
- label: 'Accueil',
- icon: 'pi pi-home',
- routerLink: '/'
- },
- {
- label: 'Se connecter',
- icon: 'pi pi-sign-in',
- routerLink : '/login'
- }
- ]
+ constructor(private cookieService: CookieService) {
}
}
diff --git a/src/app/app.config.ts b/src/app/app.config.ts
index 2e64bb1..a955765 100644
--- a/src/app/app.config.ts
+++ b/src/app/app.config.ts
@@ -1,14 +1,16 @@
-import {ApplicationConfig, provideZoneChangeDetection} from '@angular/core';
+import {ApplicationConfig, importProvidersFrom, provideZoneChangeDetection} from '@angular/core';
import {provideRouter} from '@angular/router';
import {routes} from './app.routes';
import {provideClientHydration} from '@angular/platform-browser';
import {provideHttpClient, withFetch} from '@angular/common/http';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({eventCoalescing: true}),
provideRouter(routes),
provideClientHydration(),
- provideHttpClient(withFetch())]
+ provideHttpClient(withFetch()),
+ importProvidersFrom([BrowserAnimationsModule])]
};
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 33c5f26..1acbff4 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -1,8 +1,12 @@
import {Routes} from '@angular/router';
import {LoginComponent} from './login/login.component';
import {HomeComponent} from './home/home.component';
+import {RegisterComponent} from './register/register.component';
+import {LogoutComponent} from './logout/logout.component';
export const routes: Routes = [
{path: '', component: HomeComponent},
- {path: 'login', component: LoginComponent}
+ {path: 'login', component: LoginComponent},
+ {path: 'register', component: RegisterComponent},
+ {path: 'logout', component: LogoutComponent}
];
diff --git a/src/app/header/header.component.css b/src/app/header/header.component.css
new file mode 100644
index 0000000..7f98bd0
--- /dev/null
+++ b/src/app/header/header.component.css
@@ -0,0 +1,5 @@
+img {
+ width: 100%;
+ height: 25rem;
+ object-fit: cover;
+}
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
new file mode 100644
index 0000000..d80027e
--- /dev/null
+++ b/src/app/header/header.component.html
@@ -0,0 +1,2 @@
+
+
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
new file mode 100644
index 0000000..681420c
--- /dev/null
+++ b/src/app/header/header.component.ts
@@ -0,0 +1,58 @@
+import { Component } from '@angular/core';
+import {CookieService} from 'ngx-cookie-service';
+import {MenuItem} from 'primeng/api';
+import {MenubarModule} from 'primeng/menubar';
+import {RouterOutlet} from '@angular/router';
+
+@Component({
+ selector: 'app-header',
+ standalone: true,
+ imports: [
+ MenubarModule,
+ RouterOutlet
+ ],
+ templateUrl: './header.component.html',
+ styleUrl: './header.component.css'
+})
+export class HeaderComponent {
+ items: MenuItem[] = [];
+ constructor(private cookieService: CookieService) {
+ if (this.cookieService.get('author')) {
+ this.items = [
+ {
+ label: 'Accueil',
+ icon: 'pi pi-home',
+ routerLink: '/'
+ },
+ {
+ label: 'Se déconnecter',
+ icon: 'pi pi-sign-out',
+ routerLink: '/logout'
+ },
+ {
+ label: 'Mon profil',
+ icon: 'pi pi-user',
+ routerLink: '/me'
+ }
+ ];
+ } else {
+ this.items = [
+ {
+ label: 'Accueil',
+ icon: 'pi pi-home',
+ routerLink: '/'
+ },
+ {
+ label: 'Se connecter',
+ icon: 'pi pi-sign-in',
+ routerLink: '/login'
+ },
+ {
+ label: "S'inscrire",
+ icon: 'pi pi-user-plus',
+ routerLink: '/register'
+ }
+ ];
+ }
+ }
+}
diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html
index 8c2c17e..da230c4 100644
--- a/src/app/home/home.component.html
+++ b/src/app/home/home.component.html
@@ -1,3 +1,5 @@
+
+
@@ -16,4 +18,4 @@
-{{ authors | json }}
+{{ actualAuthor | json }}
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index c00d76d..f174386 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -5,24 +5,45 @@ import {AuthorService} from '../services/author.service';
import {Author} from '../model/author';
import {JsonPipe} from '@angular/common';
import {Subscription} from 'rxjs';
+import {PostService} from '../services/post.service';
+import {Header, MessageService} from 'primeng/api';
+import {HeaderComponent} from '../header/header.component';
+import {ToastModule} from 'primeng/toast';
+import {CookieService} from 'ngx-cookie-service';
@Component({
selector: 'app-home',
standalone: true,
imports: [
AvatarModule,
- ButtonDirective,
Button,
+ HeaderComponent,
+ ToastModule,
JsonPipe
],
+ providers: [
+ MessageService,
+ ],
templateUrl: './home.component.html',
styleUrl: './home.component.css'
})
export class HomeComponent implements OnDestroy {
+ actualAuthor: Author | undefined;
authors: Author[] = []
subs: Subscription[] = []
- constructor(private authorService: AuthorService) {
+ constructor(
+ private authorService: AuthorService,
+ private postService: PostService,
+ private messageService: MessageService,
+ private cookieService: CookieService) {
+
+ if (this.cookieService.get('author')) {
+ this.actualAuthor = JSON.parse(this.cookieService.get('author'));
+ if (this.cookieService.get("just-authenticated")) {
+ this.successMessage('Connecté avec succès', `Heureux de vous revoir ${this.actualAuthor?.name}`);
+ }
+ }
this.subs.push(authorService.list()
.subscribe({
next: (authors: Author[]) => this.authors = authors,
@@ -30,6 +51,16 @@ export class HomeComponent implements OnDestroy {
}));
}
+ successMessage(summary: string, detail: string): void {
+ this.messageService.add({
+ severity: 'success',
+ summary: summary,
+ detail: detail,
+ life: 1500,
+ closable: false
+ });
+ }
+
ngOnDestroy(): void {
this.subs.forEach(sub => sub.unsubscribe());
}
diff --git a/src/app/login/login.component.html b/src/app/login/login.component.html
index 3f894c5..e05192d 100644
--- a/src/app/login/login.component.html
+++ b/src/app/login/login.component.html
@@ -1,5 +1,15 @@
+
+
-
+
-
+
+
+
+
+{{ actualAuthor | json }}
diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts
index 23028d5..2347e41 100644
--- a/src/app/login/login.component.ts
+++ b/src/app/login/login.component.ts
@@ -1,18 +1,84 @@
-import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {Component, CUSTOM_ELEMENTS_SCHEMA, OnDestroy} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {InputTextModule} from 'primeng/inputtext';
+import {Button} from 'primeng/button';
+import {AuthorService} from '../services/author.service';
+import {ToastModule} from 'primeng/toast';
+import {MessageService} from 'primeng/api';
+import {Author} from '../model/author';
+import {Subscription, switchMap} from 'rxjs';
+import {JsonPipe} from '@angular/common';
+import { CookieService } from 'ngx-cookie-service';
+import {HeaderComponent} from '../header/header.component';
+import {Router} from '@angular/router';
@Component({
selector: 'app-login',
standalone: true,
imports: [
FormsModule,
- InputTextModule
+ InputTextModule,
+ Button,
+ ToastModule,
+ JsonPipe,
+ HeaderComponent
],
templateUrl: './login.component.html',
- styleUrl: './login.component.css'
+ styleUrl: './login.component.css',
+ providers: [
+ MessageService,
+ ]
})
-export class LoginComponent {
+export class LoginComponent implements OnDestroy {
name: string = "";
+ actualAuthor: Author | undefined;
+ password: string = "";
+ confirmPassword: string = "";
+ subs: Subscription[] = [];
+
+ constructor(private authorService: AuthorService,
+ private messageService: MessageService,
+ private cookieService: CookieService,
+ private router: Router) {}
+
+ sendLogins(): void {
+ if (this.password === this.confirmPassword) {
+ this.subs.push
+ (
+ this.authorService.login(this.name, this.password).pipe(
+ switchMap((tokenObj: any) => this.authorService.me(tokenObj.token)))
+ .subscribe({
+ next: (author: Author) => {
+ this.cookieService.set("author", JSON.stringify(author));
+ this.cookieService.set("just-authenticated", "true");
+ this.getAuthorCookie();
+ this.router.navigate(['/']);
+ },
+ error: (err) => this.failureMessage('Erreur de connexion', err.message)
+ })
+ );
+
+ } else {
+ this.failureMessage('Erreur de connexion', 'Les deux mots de passe ne correspondent pas')
+ }
+ }
+
+ getAuthorCookie(): void {
+ this.actualAuthor = JSON.parse(this.cookieService.get("author"));
+ }
+
+ failureMessage(summary: string, detail: string): void {
+ this.messageService.add({
+ severity: 'error',
+ summary: summary,
+ detail: detail,
+ life: 1500,
+ closable: false
+ });
+ }
+
+ ngOnDestroy(): void {
+ this.subs.forEach(sub => sub.unsubscribe());
+ }
}
diff --git a/src/app/logout/logout.component.css b/src/app/logout/logout.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/logout/logout.component.html b/src/app/logout/logout.component.html
new file mode 100644
index 0000000..ac705a5
--- /dev/null
+++ b/src/app/logout/logout.component.html
@@ -0,0 +1,2 @@
+
+Déconnexion...
diff --git a/src/app/logout/logout.component.ts b/src/app/logout/logout.component.ts
new file mode 100644
index 0000000..2dff5a0
--- /dev/null
+++ b/src/app/logout/logout.component.ts
@@ -0,0 +1,24 @@
+import {Component, OnInit} from '@angular/core';
+import {CookieService} from 'ngx-cookie-service';
+import {HeaderComponent} from '../header/header.component';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-logout',
+ standalone: true,
+ imports: [
+ HeaderComponent
+ ],
+ templateUrl: './logout.component.html',
+ styleUrl: './logout.component.css'
+})
+export class LogoutComponent implements OnInit{
+
+ constructor(private cookiesService: CookieService,
+ private router: Router) { }
+ ngOnInit(): void {
+ this.cookiesService.deleteAll();
+ this.router.navigate(['/']);
+ }
+
+}
diff --git a/src/app/model/author.ts b/src/app/model/author.ts
index 2f8ff75..2b6c06a 100644
--- a/src/app/model/author.ts
+++ b/src/app/model/author.ts
@@ -2,4 +2,5 @@ export interface Author {
id: string
name: string
avatar: string
+ role: string
}
diff --git a/src/app/register/register.component.css b/src/app/register/register.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/register/register.component.html b/src/app/register/register.component.html
new file mode 100644
index 0000000..f3fb26c
--- /dev/null
+++ b/src/app/register/register.component.html
@@ -0,0 +1,3 @@
+
+
+register works!
diff --git a/src/app/register/register.component.ts b/src/app/register/register.component.ts
new file mode 100644
index 0000000..f87ae57
--- /dev/null
+++ b/src/app/register/register.component.ts
@@ -0,0 +1,15 @@
+import { Component } from '@angular/core';
+import {HeaderComponent} from '../header/header.component';
+
+@Component({
+ selector: 'app-register',
+ standalone: true,
+ imports: [
+ HeaderComponent
+ ],
+ templateUrl: './register.component.html',
+ styleUrl: './register.component.css'
+})
+export class RegisterComponent {
+
+}
diff --git a/src/app/services/author.service.ts b/src/app/services/author.service.ts
index c02134e..bb5c67c 100644
--- a/src/app/services/author.service.ts
+++ b/src/app/services/author.service.ts
@@ -1,5 +1,5 @@
import {Injectable} from '@angular/core';
-import {HttpClient} from '@angular/common/http';
+import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Author} from '../model/author';
@@ -8,11 +8,19 @@ import {Author} from '../model/author';
})
export class AuthorService {
- constructor(private httpClient: HttpClient) {
-
- }
+ constructor(private httpClient: HttpClient) {}
list(): Observable {
return this.httpClient.get("http://localhost:8080/api/authors");
}
+
+ login(name: string, password: string) {
+ return this.httpClient.post("http://localhost:8080/api/authors/login", {name: name, password: password})
+ }
+
+ me(token: string): Observable {
+ const headers = new HttpHeaders().set("Authorization", "Bearer " + token);
+ console.log(headers)
+ return this.httpClient.get("http://localhost:8080/api/authors/me", {'headers': headers});
+ }
}