Début de formulaire pour les posts

This commit is contained in:
Guams 2024-12-25 18:05:01 +01:00
parent 832119a4fc
commit 1168d9c349
12 changed files with 188 additions and 81 deletions

58
package-lock.json generated
View File

@ -23,6 +23,7 @@
"ngx-cookie-service": "^18.0.0", "ngx-cookie-service": "^18.0.0",
"primeicons": "^7.0.0", "primeicons": "^7.0.0",
"primeng": "^17.18.10", "primeng": "^17.18.10",
"quill": "^2.0.3",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.14.10" "zone.js": "~0.14.10"
@ -7057,6 +7058,11 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@ -9055,6 +9061,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
},
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -9062,6 +9078,11 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
},
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@ -10484,6 +10505,11 @@
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
} }
}, },
"node_modules/parchment": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
"integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A=="
},
"node_modules/parent-module": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -11001,6 +11027,38 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/quill": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz",
"integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==",
"dependencies": {
"eventemitter3": "^5.0.1",
"lodash-es": "^4.17.21",
"parchment": "^3.0.0",
"quill-delta": "^5.1.0"
},
"engines": {
"npm": ">=8.2.3"
}
},
"node_modules/quill-delta": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
"integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==",
"dependencies": {
"fast-diff": "^1.3.0",
"lodash.clonedeep": "^4.5.0",
"lodash.isequal": "^4.5.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/quill/node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
},
"node_modules/randombytes": { "node_modules/randombytes": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",

View File

@ -26,6 +26,7 @@
"ngx-cookie-service": "^18.0.0", "ngx-cookie-service": "^18.0.0",
"primeicons": "^7.0.0", "primeicons": "^7.0.0",
"primeng": "^17.18.10", "primeng": "^17.18.10",
"quill": "^2.0.3",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.14.10" "zone.js": "~0.14.10"

View File

@ -4,8 +4,10 @@ import {HomeComponent} from './home/home.component';
import {RegisterComponent} from './register/register.component'; import {RegisterComponent} from './register/register.component';
import {LogoutComponent} from './logout/logout.component'; import {LogoutComponent} from './logout/logout.component';
import {NotFoundComponent} from './not-found/not-found.component'; import {NotFoundComponent} from './not-found/not-found.component';
import {authGuard} from './auth.guard'; import {authGuard} from './guards/auth.guard';
import {ProfileComponent} from './profile/profile.component'; import {ProfileComponent} from './profile/profile.component';
import {NewPostComponent} from './new-post/new-post.component';
import {writerGuard} from './guards/writer.guard';
export const routes: Routes = [ export const routes: Routes = [
{path: '', component: HomeComponent}, {path: '', component: HomeComponent},
@ -13,5 +15,6 @@ export const routes: Routes = [
{path: 'register', component: RegisterComponent, canActivate: [authGuard]}, {path: 'register', component: RegisterComponent, canActivate: [authGuard]},
{path: 'logout', component: LogoutComponent}, {path: 'logout', component: LogoutComponent},
{path: 'profile/:authorId', component: ProfileComponent}, {path: 'profile/:authorId', component: ProfileComponent},
{path: 'new-post', component: NewPostComponent, canActivate: [writerGuard]},
{path: '**', component: NotFoundComponent} {path: '**', component: NotFoundComponent}
]; ];

View File

@ -1,9 +1,9 @@
import {Component} from '@angular/core'; import { Component } from '@angular/core';
import {CookieService} from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';
import {MenuItem} from 'primeng/api'; import { MenuItem } from 'primeng/api';
import {MenubarModule} from 'primeng/menubar'; import { MenubarModule } from 'primeng/menubar';
import {ToastModule} from 'primeng/toast'; import { ToastModule } from 'primeng/toast';
import {Author} from '../model/author'; import { Author } from '../models/author';
@Component({ @Component({
selector: 'app-header', selector: 'app-header',
@ -13,78 +13,114 @@ import {Author} from '../model/author';
ToastModule ToastModule
], ],
templateUrl: './header.component.html', templateUrl: './header.component.html',
styleUrl: './header.component.css' styleUrls: ['./header.component.css']
}) })
export class HeaderComponent { export class HeaderComponent {
actualAuthor: Author | undefined; actualAuthor: Author | undefined;
items: MenuItem[] = []; items: MenuItem[] = [];
constructor(private cookieService: CookieService) { constructor(private cookieService: CookieService) {
if (this.cookieService.get('author')) { this.initializeMenu();
this.actualAuthor = JSON.parse(this.cookieService.get('author')); }
this.items = [
{ private initializeMenu(): void {
label: 'Accueil', const authorData = this.cookieService.get('author');
icon: 'pi pi-home', this.actualAuthor = authorData ? JSON.parse(authorData) : undefined;
routerLink: '/'
}, if (this.actualAuthor) {
{ this.items = this.getMenuForAuthor(this.actualAuthor);
label: 'Mes posts',
icon: 'pi pi-file-edit',
items: [
{
label: 'Ajouter un post',
icon: 'pi pi-plus',
routerLink: 'new-post'
},
{
label: 'Voir mes posts',
icon: 'pi pi-eye',
routerLink: ['posts', `${this.actualAuthor?.id}`]
}
]
},
{
label: `${this.actualAuthor?.name.toUpperCase()}`,
icon: 'pi pi-user',
items: [
{
label: 'Voir mon profil',
icon: 'pi pi-user',
routerLink: [`/profile`, `${this.actualAuthor?.id}`]
},
{
label: 'Se déconnecter',
icon: 'pi pi-sign-out',
routerLink: '/logout'
}
]
}
];
} else { } else {
this.items = [ this.items = this.getDefaultMenu();
{
label: 'Accueil',
icon: 'pi pi-home',
routerLink: '/'
},
{
label: "S'authentifier",
icon: 'pi pi-sign-in',
items: [
{
label: 'Se connecter',
icon: 'pi pi-sign-in',
routerLink: '/login'
},
{
label: "S'inscrire",
icon: 'pi pi-user-plus',
routerLink: '/register'
}
]
}
];
} }
} }
private getMenuForAuthor(author: Author): MenuItem[] {
const commonItems: MenuItem[] = [
{
label: 'Accueil',
icon: 'pi pi-home',
routerLink: '/'
}
];
if (author.role === 'WRITER') {
return [
...commonItems,
this.getWriterMenu(author),
this.getUserMenu(author)
];
} else if (author.role === 'ADMIN') {
return [
...commonItems,
this.getAdminMenu(),
this.getUserMenu(author)
];
} else if (author.role === 'READER') {
return [
...commonItems,
this.getUserMenu(author)
];
}
return commonItems;
}
private getWriterMenu(author: Author): MenuItem {
return {
label: 'Mes posts',
icon: 'pi pi-file-edit',
items: [
{ label: 'Ajouter un post', icon: 'pi pi-plus', routerLink: 'new-post' },
{ label: 'Voir mes posts', icon: 'pi pi-eye', routerLink: ['posts', `${author.id}`] }
]
};
}
private getAdminMenu(): MenuItem {
return {
label: 'Administration',
icon: 'pi pi-cog',
items: [
{
label: 'Gérer les posts',
icon: 'pi pi-file',
routerLink: '/admin/posts'
},
{
label: 'Gérer les auteurs',
icon: 'pi pi-users',
routerLink: '/admin/authors'
}
]
};
}
private getUserMenu(author: Author): MenuItem {
return {
label: author.name.toUpperCase(),
icon: 'pi pi-user',
items: [
{ label: 'Voir mon profil', icon: 'pi pi-user', routerLink: [`/profile`, `${author.id}`] },
{ label: 'Se déconnecter', icon: 'pi pi-sign-out', routerLink: '/logout' }
]
};
}
private getDefaultMenu(): MenuItem[] {
return [
{
label: 'Accueil',
icon: 'pi pi-home',
routerLink: '/'
},
{
label: "S'authentifier",
icon: 'pi pi-sign-in',
items: [
{ label: 'Se connecter', icon: 'pi pi-sign-in', routerLink: '/login' },
{ label: "S'inscrire", icon: 'pi pi-user-plus', routerLink: '/register' }
]
}
];
}
} }

View File

@ -2,13 +2,15 @@ import {Component, OnDestroy} from '@angular/core';
import {AvatarModule} from 'primeng/avatar'; import {AvatarModule} from 'primeng/avatar';
import {Button} from 'primeng/button'; import {Button} from 'primeng/button';
import {AuthorService} from '../services/author.service'; import {AuthorService} from '../services/author.service';
import {Author} from '../model/author'; import {Author} from '../models/author';
import {JsonPipe} from '@angular/common'; import {JsonPipe} from '@angular/common';
import {Subscription} from 'rxjs'; import {Subscription} from 'rxjs';
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {HeaderComponent} from '../header/header.component'; import {HeaderComponent} from '../header/header.component';
import {ToastModule} from 'primeng/toast'; import {ToastModule} from 'primeng/toast';
import {CookieService} from 'ngx-cookie-service'; import {CookieService} from 'ngx-cookie-service';
import {PostService} from '../services/post.service';
import {Post} from '../models/post';
@Component({ @Component({
selector: 'app-home', selector: 'app-home',
@ -25,20 +27,20 @@ import {CookieService} from 'ngx-cookie-service';
}) })
export class HomeComponent implements OnDestroy { export class HomeComponent implements OnDestroy {
actualAuthor: Author | undefined; actualAuthor: Author | undefined;
authors: Author[] = [] posts: Post[] = []
subs: Subscription[] = [] subs: Subscription[] = []
constructor( constructor(
private authorService: AuthorService,
private messageService: MessageService, private messageService: MessageService,
private postService: PostService,
private cookieService: CookieService) { private cookieService: CookieService) {
if (this.cookieService.get('author')) { if (this.cookieService.get('author')) {
this.actualAuthor = JSON.parse(this.cookieService.get('author')); this.actualAuthor = JSON.parse(this.cookieService.get('author'));
} }
this.subs.push(this.authorService.list() this.subs.push(this.postService.list()
.subscribe({ .subscribe({
next: (authors: Author[]) => this.authors = authors, next: (posts: Post[]) => this.posts = posts,
error: (err) => console.error(err.message), error: (err) => console.error(err.message),
})); }));
} }

View File

@ -5,7 +5,7 @@ import {Button} from 'primeng/button';
import {AuthorService} from '../services/author.service'; import {AuthorService} from '../services/author.service';
import {ToastModule} from 'primeng/toast'; import {ToastModule} from 'primeng/toast';
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {Author} from '../model/author'; import {Author} from '../models/author';
import {Subscription, switchMap} from 'rxjs'; import {Subscription, switchMap} from 'rxjs';
import {JsonPipe} from '@angular/common'; import {JsonPipe} from '@angular/common';
import { CookieService } from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';

View File

@ -2,7 +2,7 @@ import {Component, OnDestroy} from '@angular/core';
import {HeaderComponent} from '../header/header.component'; import {HeaderComponent} from '../header/header.component';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {CookieService} from 'ngx-cookie-service'; import {CookieService} from 'ngx-cookie-service';
import {Author} from '../model/author'; import {Author} from '../models/author';
import {Subscription} from 'rxjs'; import {Subscription} from 'rxjs';
import {AuthorService} from '../services/author.service'; import {AuthorService} from '../services/author.service';
import {JsonPipe} from '@angular/common'; import {JsonPipe} from '@angular/common';

View File

@ -1,7 +1,7 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http'; import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {Author} from '../model/author'; import {Author} from '../models/author';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'

View File

@ -1,9 +1,16 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import {Observable} from 'rxjs';
import {Post} from '../models/post';
import {HttpClient} from '@angular/common/http';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class PostService { export class PostService {
url: string = 'http://localhost:8080/api/posts';
constructor(private httpClient: HttpClient) {}
constructor() { } list(): Observable<Post[]> {
return this.httpClient.get<Post[]>("http://localhost:8080/api/posts");
}
} }