Session storage 100% fonctionnel

This commit is contained in:
guams 2025-04-19 10:27:00 +02:00
parent 3c4053ffcc
commit 1625dd3e46
15 changed files with 36 additions and 37 deletions

View File

@ -28,6 +28,7 @@
} }
], ],
"styles": [ "styles": [
"@angular/material/prebuilt-themes/azure-blue.css",
"src/styles.css" "src/styles.css"
], ],
"scripts": [] "scripts": []
@ -92,6 +93,7 @@
} }
], ],
"styles": [ "styles": [
"@angular/material/prebuilt-themes/magenta-violet.css",
"src/styles.css" "src/styles.css"
], ],
"scripts": [] "scripts": []

View File

@ -12,10 +12,12 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^18.2.0", "@angular/animations": "^18.2.0",
"@angular/cdk": "^18.2.14",
"@angular/common": "^18.2.0", "@angular/common": "^18.2.0",
"@angular/compiler": "^18.2.0", "@angular/compiler": "^18.2.0",
"@angular/core": "^18.2.0", "@angular/core": "^18.2.0",
"@angular/forms": "^18.2.0", "@angular/forms": "^18.2.0",
"@angular/material": "^18.2.14",
"@angular/platform-browser": "^18.2.0", "@angular/platform-browser": "^18.2.0",
"@angular/platform-browser-dynamic": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0",
"@angular/platform-server": "^18.2.0", "@angular/platform-server": "^18.2.0",

View File

@ -1,5 +1,5 @@
<router-outlet></router-outlet> <router-outlet></router-outlet>
@if (isBrowser()) { @if (isBrowser() && (authService.isSessionExpired() && authService.isAuthenticated())) {
<p-dialog header="ATTENTION !" [modal]="true" [closable]="false" [visible]="isSessionExpired"> <p-dialog header="ATTENTION !" [modal]="true" [closable]="false" [visible]="isSessionExpired">
<span>Votre session a <strong>expiré</strong> ! Il va falloir se reconnecter.</span> <span>Votre session a <strong>expiré</strong> ! Il va falloir se reconnecter.</span>
<div class="expired-dialog"> <div class="expired-dialog">

View File

@ -7,7 +7,7 @@ import {DialogModule} from 'primeng/dialog';
import {isPlatformBrowser} from '@angular/common'; import {isPlatformBrowser} from '@angular/common';
import {Button} from 'primeng/button'; import {Button} from 'primeng/button';
import {AuthService} from './auth.service'; import {AuthService} from './auth.service';
import {CookieService} from 'ngx-cookie-service'; import {Router} from '@angular/router';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -23,8 +23,8 @@ export class AppComponent implements OnInit {
isSessionExpired: boolean = false; isSessionExpired: boolean = false;
constructor(@Inject(PLATFORM_ID) private platformId: object, constructor(@Inject(PLATFORM_ID) private platformId: object,
private authService: AuthService, protected authService: AuthService,
private cookieService: CookieService) { private router: Router,) {
} }
isBrowser(): boolean { isBrowser(): boolean {
@ -34,6 +34,7 @@ export class AppComponent implements OnInit {
setSessionExpiredFalse(): void { setSessionExpiredFalse(): void {
this.isSessionExpired = false; this.isSessionExpired = false;
this.authService.setSessionExpired(false); this.authService.setSessionExpired(false);
this.router.navigate(['/logout']);
} }
ngOnInit(): void { ngOnInit(): void {

View File

@ -5,6 +5,7 @@ import {routes} from './app.routes';
import {provideClientHydration} from '@angular/platform-browser'; import {provideClientHydration} from '@angular/platform-browser';
import {provideHttpClient, withFetch} from '@angular/common/http'; import {provideHttpClient, withFetch} from '@angular/common/http';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [ providers: [
@ -12,5 +13,5 @@ export const appConfig: ApplicationConfig = {
provideRouter(routes), provideRouter(routes),
provideClientHydration(), provideClientHydration(),
provideHttpClient(withFetch()), provideHttpClient(withFetch()),
importProvidersFrom([BrowserAnimationsModule])] importProvidersFrom([BrowserAnimationsModule]), provideAnimationsAsync()]
}; };

View File

@ -1,5 +1,4 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {CookieService} from 'ngx-cookie-service';
import {Author} from './models/author'; import {Author} from './models/author';
import {BehaviorSubject} from 'rxjs'; import {BehaviorSubject} from 'rxjs';
import {DateTime} from 'luxon'; import {DateTime} from 'luxon';
@ -11,7 +10,7 @@ export class AuthService {
private sessionExpiredSubject = new BehaviorSubject<boolean>(false); private sessionExpiredSubject = new BehaviorSubject<boolean>(false);
sessionExpired$ = this.sessionExpiredSubject.asObservable(); sessionExpired$ = this.sessionExpiredSubject.asObservable();
constructor(private cookieService: CookieService) { constructor() {
this.checkSessionExpiration(); this.checkSessionExpiration();
} }

View File

@ -5,7 +5,7 @@
<span>{{ category }}</span> <span>{{ category }}</span>
<em>Publié le {{ date | date : "dd/MM/yyyy à HH:mm" }}</em> <em>Publié le {{ date | date : "dd/MM/yyyy à HH:mm" }}</em>
<span class="desc">{{ description }}</span> <span class="desc">{{ description }}</span>
<p-button routerLink="post/{{ postId }}" label="Lire la suite"/> <button mat-flat-button routerLink="post/{{ postId }}" >Lire la suite</button>
<a routerLink="/profile/{{ authorId }}" class="user-profile"> <a routerLink="/profile/{{ authorId }}" class="user-profile">
@if (authorProfilePicture) { @if (authorProfilePicture) {
<p-avatar image="data:image/jpeg;base64,{{ authorProfilePicture }}" shape="circle" styleClass="mr-2" <p-avatar image="data:image/jpeg;base64,{{ authorProfilePicture }}" shape="circle" styleClass="mr-2"

View File

@ -4,6 +4,7 @@ import {CardModule} from 'primeng/card';
import {DatePipe} from '@angular/common'; import {DatePipe} from '@angular/common';
import {RouterLink} from '@angular/router'; import {RouterLink} from '@angular/router';
import {AvatarModule} from 'primeng/avatar'; import {AvatarModule} from 'primeng/avatar';
import {MatButton, MatFabButton} from '@angular/material/button';
@Component({ @Component({
selector: 'app-post-home', selector: 'app-post-home',
@ -13,7 +14,9 @@ import {AvatarModule} from 'primeng/avatar';
CardModule, CardModule,
DatePipe, DatePipe,
RouterLink, RouterLink,
AvatarModule AvatarModule,
MatButton,
MatFabButton
], ],
templateUrl: './post-home.component.html', templateUrl: './post-home.component.html',
styleUrl: './post-home.component.css' styleUrl: './post-home.component.css'

View File

@ -7,7 +7,6 @@ import {Subscription, switchMap} from 'rxjs';
import {AuthorService} from '../../services/author.service'; import {AuthorService} from '../../services/author.service';
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {FileSelectEvent, FileUploadModule} from 'primeng/fileupload'; import {FileSelectEvent, FileUploadModule} from 'primeng/fileupload';
import {CookieService} from 'ngx-cookie-service';
import {Author} from '../../models/author'; import {Author} from '../../models/author';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {AuthService} from '../../auth.service'; import {AuthService} from '../../auth.service';
@ -38,7 +37,6 @@ export class UpdateProfileFormComponent implements OnDestroy {
constructor(private formBuilder: FormBuilder, constructor(private formBuilder: FormBuilder,
private authorService: AuthorService, private authorService: AuthorService,
private messageService: MessageService, private messageService: MessageService,
private cookieService: CookieService,
private authService: AuthService, private authService: AuthService,
private router: Router, private router: Router,
) { ) {
@ -92,7 +90,7 @@ export class UpdateProfileFormComponent implements OnDestroy {
next: (author: Author) => { next: (author: Author) => {
this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès"); this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès");
this.updatedAuthorEvent.emit(author); this.updatedAuthorEvent.emit(author);
this.cookieService.set('author', JSON.stringify(author)); sessionStorage.setItem('author', JSON.stringify(author));
this.router.navigate(['/']); this.router.navigate(['/']);
}, },
error: (err) => { error: (err) => {
@ -104,7 +102,7 @@ export class UpdateProfileFormComponent implements OnDestroy {
next: (author: Author) => { next: (author: Author) => {
this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès"); this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès");
this.updatedAuthorEvent.emit(author); this.updatedAuthorEvent.emit(author);
this.cookieService.set('author', JSON.stringify(author)); sessionStorage.setItem('author', JSON.stringify(author));
this.router.navigate(['/']); this.router.navigate(['/']);
}, },
error: (err) => { error: (err) => {

View File

@ -1,17 +1,13 @@
import {CanActivateFn, Router} from '@angular/router'; import {CanActivateFn, Router} from '@angular/router';
import {inject} from '@angular/core'; import {inject} from '@angular/core';
import {CookieService} from 'ngx-cookie-service';
import {AuthService} from '../auth.service'; import {AuthService} from '../auth.service';
import {Role} from '../models/role'; import {Role} from '../models/role';
export const adminGuard: CanActivateFn = (route, state) => { export const adminGuard: CanActivateFn = (route, state) => {
const router = inject(Router); const router = inject(Router);
const cookieService = inject(CookieService);
const authService: AuthService = inject(AuthService); const authService: AuthService = inject(AuthService);
if ((authService.isAuthenticated() && JSON.parse(sessionStorage.getItem("author")!).role !== Role.ADMIN) || !authService.isAuthenticated()) {
if ((authService.isAuthenticated() && JSON.parse(cookieService.get("author")).role !== Role.ADMIN) || !authService.isAuthenticated()) {
router.navigate(['/']); router.navigate(['/']);
} }
return true; return true;
}; };

View File

@ -1,11 +1,9 @@
import {CanActivateFn, Router} from '@angular/router'; import {CanActivateFn, Router} from '@angular/router';
import {inject} from '@angular/core'; import {inject} from '@angular/core';
import {CookieService} from 'ngx-cookie-service';
export const authGuard: CanActivateFn = (route, state) => { export const authGuard: CanActivateFn = (route, state) => {
const router = inject(Router); const router = inject(Router);
const cookieService = inject(CookieService); if (sessionStorage.getItem("author") !== null || sessionStorage.getItem("token") !== null) {
if (cookieService.check("author") || cookieService.check("token")) {
router.navigate(['/']); router.navigate(['/']);
} }

View File

@ -7,7 +7,6 @@ import {ToastModule} from 'primeng/toast';
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {Author} from '../../models/author'; import {Author} from '../../models/author';
import {Subscription, switchMap} from 'rxjs'; import {Subscription, switchMap} from 'rxjs';
import {CookieService} from 'ngx-cookie-service';
import {HeaderComponent} from '../../components/header/header.component'; import {HeaderComponent} from '../../components/header/header.component';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {ConfigurationService} from '../../configuration.service'; import {ConfigurationService} from '../../configuration.service';

View File

@ -1,9 +1,7 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {CookieService} from 'ngx-cookie-service';
import {HeaderComponent} from '../../components/header/header.component'; import {HeaderComponent} from '../../components/header/header.component';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {ConfigurationService} from '../../configuration.service';
@Component({ @Component({
selector: 'app-logout', selector: 'app-logout',
@ -14,19 +12,16 @@ import {ConfigurationService} from '../../configuration.service';
templateUrl: './logout.component.html', templateUrl: './logout.component.html',
styleUrl: './logout.component.css' styleUrl: './logout.component.css'
}) })
export class LogoutComponent implements OnInit{ export class LogoutComponent implements OnInit {
constructor(private messageService: MessageService,
private router: Router) {
}
constructor(private cookieService: CookieService,
private messageService: MessageService,
private router: Router,
private configurationService: ConfigurationService,) { }
ngOnInit(): void { ngOnInit(): void {
const routes: string[] = ['/', '/login', '/register', '/logout', '/profile', '/post', '/new-post', '/admin'] sessionStorage.removeItem("author");
Object.keys(this.cookieService.getAll()).forEach(key => { sessionStorage.removeItem("token");
routes.forEach(route => { sessionStorage.removeItem("token-expiration-date");
this.cookieService.delete(key, route, this.configurationService.getDomain());
})
});
this.router.navigate(['/']).then(() => this.successMessage('Déconnexion', 'Vous avez été deconnecté avec succès')); this.router.navigate(['/']).then(() => this.successMessage('Déconnexion', 'Vous avez été deconnecté avec succès'));
} }

View File

@ -7,9 +7,11 @@
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="icon.jpg"> <link rel="icon" type="image/x-icon" href="icon.jpg">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head> </head>
<body> <body class="mat-typography">
<app-root></app-root> <app-root></app-root>
<footer class="footer"> <footer class="footer">
<p class="footer-creator">Site web réalisé par <strong>Guams</strong>.</p> <p class="footer-creator">Site web réalisé par <strong>Guams</strong>.</p>

View File

@ -53,3 +53,6 @@ app-root {
.footer-link:hover { .footer-link:hover {
text-decoration: underline; text-decoration: underline;
} }
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }