FEAT : Ajout des commentaires
This commit is contained in:
@@ -4,6 +4,7 @@ import local.epul4a.fotosharing.model.Photo;
|
|||||||
import local.epul4a.fotosharing.model.Utilisateur;
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
import local.epul4a.fotosharing.repository.PhotoRepository;
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
import local.epul4a.fotosharing.security.CustomUserDetails;
|
import local.epul4a.fotosharing.security.CustomUserDetails;
|
||||||
|
import local.epul4a.fotosharing.service.CommentaireService;
|
||||||
import local.epul4a.fotosharing.service.PhotoService;
|
import local.epul4a.fotosharing.service.PhotoService;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.PathResource;
|
import org.springframework.core.io.PathResource;
|
||||||
@@ -25,10 +26,12 @@ public class PhotoController {
|
|||||||
|
|
||||||
private final PhotoService photoService;
|
private final PhotoService photoService;
|
||||||
private final PhotoRepository photoRepository;
|
private final PhotoRepository photoRepository;
|
||||||
|
private final CommentaireService commentaireService;
|
||||||
|
|
||||||
public PhotoController(PhotoService photoService, PhotoRepository photoRepository) {
|
public PhotoController(PhotoService photoService, PhotoRepository photoRepository, CommentaireService commentaireService) {
|
||||||
this.photoService = photoService;
|
this.photoService = photoService;
|
||||||
this.photoRepository = photoRepository;
|
this.photoRepository = photoRepository;
|
||||||
|
this.commentaireService = commentaireService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/upload")
|
@GetMapping("/upload")
|
||||||
@@ -91,6 +94,37 @@ public class PhotoController {
|
|||||||
return "galerie";
|
return "galerie";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/photo/{id}")
|
||||||
|
public String viewPhoto(@PathVariable Long id,
|
||||||
|
Model model,
|
||||||
|
Authentication auth) {
|
||||||
|
|
||||||
|
Photo photo = photoRepository.findById(id).orElse(null);
|
||||||
|
if (photo == null) {
|
||||||
|
return "redirect:/galerie";
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("photo", photo);
|
||||||
|
model.addAttribute("commentaires", commentaireService.listByPhoto(id));
|
||||||
|
|
||||||
|
// utilisateur connecté (peut être null si visiteur)
|
||||||
|
String currentUser = (auth != null ? auth.getName() : null);
|
||||||
|
model.addAttribute("currentUser", currentUser);
|
||||||
|
|
||||||
|
return "photo-detail";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/photo/{id}/comment")
|
||||||
|
public String addComment(@PathVariable Long id,
|
||||||
|
@RequestParam String contenu,
|
||||||
|
Authentication auth) {
|
||||||
|
if (auth == null) {
|
||||||
|
return "redirect:/login";
|
||||||
|
}
|
||||||
|
String email = auth.getName();
|
||||||
|
commentaireService.addComment(id, email, contenu);
|
||||||
|
return "redirect:/photo/" + id;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package local.epul4a.fotosharing.repository;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Commentaire;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface CommentaireRepository extends JpaRepository<Commentaire, Long> {
|
||||||
|
|
||||||
|
List<Commentaire> findByPhoto_IdOrderByDateCommentaireAsc(Long photoId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ public class SecurityConfig {
|
|||||||
http
|
http
|
||||||
.userDetailsService(customUserDetailsService) // Utiliser directement le UserDetailsService
|
.userDetailsService(customUserDetailsService) // Utiliser directement le UserDetailsService
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/register", "/login", "/css/**", "/js/**", "/photo/*/raw", "/galerie").permitAll()
|
.requestMatchers("/register", "/login", "/css/**", "/js/**", "/galerie", "/photo/*", "/photo/*/raw").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.formLogin(form -> form
|
.formLogin(form -> form
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package local.epul4a.fotosharing.service;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Commentaire;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface CommentaireService {
|
||||||
|
List<Commentaire> listByPhoto(Long photoId);
|
||||||
|
void addComment(Long photoId, String email, String contenu);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package local.epul4a.fotosharing.service.impl;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Commentaire;
|
||||||
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.CommentaireRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.UtilisateurRepository;
|
||||||
|
import local.epul4a.fotosharing.service.CommentaireService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CommentaireServiceImpl implements CommentaireService {
|
||||||
|
|
||||||
|
private final CommentaireRepository commentaireRepository;
|
||||||
|
private final PhotoRepository photoRepository;
|
||||||
|
private final UtilisateurRepository utilisateurRepository;
|
||||||
|
|
||||||
|
public CommentaireServiceImpl(CommentaireRepository commentaireRepository,
|
||||||
|
PhotoRepository photoRepository,
|
||||||
|
UtilisateurRepository utilisateurRepository) {
|
||||||
|
this.commentaireRepository = commentaireRepository;
|
||||||
|
this.photoRepository = photoRepository;
|
||||||
|
this.utilisateurRepository = utilisateurRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Commentaire> listByPhoto(Long photoId) {
|
||||||
|
return commentaireRepository.findByPhoto_IdOrderByDateCommentaireAsc(photoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComment(Long photoId, String email, String contenu) {
|
||||||
|
Photo photo = photoRepository.findById(photoId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Photo introuvable"));
|
||||||
|
Utilisateur user = utilisateurRepository.findByEmail(email)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Utilisateur introuvable"));
|
||||||
|
|
||||||
|
Commentaire c = new Commentaire();
|
||||||
|
c.setPhoto(photo);
|
||||||
|
c.setAuteur(user);
|
||||||
|
c.setContenu(contenu);
|
||||||
|
c.setDateCommentaire(LocalDateTime.now());
|
||||||
|
|
||||||
|
commentaireRepository.save(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<li th:each="p : ${photos}">
|
<li th:each="p : ${photos}">
|
||||||
<span th:text="${p.nomFichierOriginal}">nom</span>
|
<span th:text="${p.nomFichierOriginal}">nom</span>
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<li th:each="p : ${photos}">
|
<li th:each="p : ${photos}">
|
||||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
62
src/main/resources/templates/photo-detail.html
Normal file
62
src/main/resources/templates/photo-detail.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Détail de la photo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Détail de la photo</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a th:href="@{/}">Accueil</a> |
|
||||||
|
<a th:href="@{/galerie}">Galerie publique</a> |
|
||||||
|
<a th:href="@{/mes-photos}">Mes photos</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Affichage de la photo -->
|
||||||
|
<div>
|
||||||
|
<img th:src="@{'/photo/' + ${photo.id} + '/raw'}"
|
||||||
|
alt="Photo"
|
||||||
|
style="max-width:500px; border:1px solid #ccc; margin:20px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Infos -->
|
||||||
|
<ul>
|
||||||
|
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
||||||
|
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||||
|
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||||
|
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Commentaires -->
|
||||||
|
<h2>Commentaires</h2>
|
||||||
|
<div th:if="${#lists.isEmpty(commentaires)}">
|
||||||
|
<p>Aucun commentaire pour l'instant.</p>
|
||||||
|
</div>
|
||||||
|
<ul th:if="${!#lists.isEmpty(commentaires)}">
|
||||||
|
<li th:each="c : ${commentaires}">
|
||||||
|
<strong th:text="${c.auteur.email}">Auteur</strong> :
|
||||||
|
<span th:text="${c.contenu}"></span>
|
||||||
|
<em>(<span th:text="${c.dateCommentaire}"></span>)</em>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- Formulaire d'ajout de commentaire -->
|
||||||
|
<div th:if="${currentUser}">
|
||||||
|
<h3>Ajouter un commentaire</h3>
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
||||||
|
<textarea name="contenu" rows="3" cols="50"></textarea><br/>
|
||||||
|
<button type="submit">Envoyer</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div th:if="${currentUser == null}">
|
||||||
|
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@
|
|||||||
<li th:each="p : ${photos}">
|
<li th:each="p : ${photos}">
|
||||||
<span th:text="${p.nomFichierOriginal}">nom</span>
|
<span th:text="${p.nomFichierOriginal}">nom</span>
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<li th:each="p : ${photos}">
|
<li th:each="p : ${photos}">
|
||||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
62
target/classes/templates/photo-detail.html
Normal file
62
target/classes/templates/photo-detail.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Détail de la photo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Détail de la photo</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a th:href="@{/}">Accueil</a> |
|
||||||
|
<a th:href="@{/galerie}">Galerie publique</a> |
|
||||||
|
<a th:href="@{/mes-photos}">Mes photos</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Affichage de la photo -->
|
||||||
|
<div>
|
||||||
|
<img th:src="@{'/photo/' + ${photo.id} + '/raw'}"
|
||||||
|
alt="Photo"
|
||||||
|
style="max-width:500px; border:1px solid #ccc; margin:20px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Infos -->
|
||||||
|
<ul>
|
||||||
|
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
||||||
|
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||||
|
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||||
|
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Commentaires -->
|
||||||
|
<h2>Commentaires</h2>
|
||||||
|
<div th:if="${#lists.isEmpty(commentaires)}">
|
||||||
|
<p>Aucun commentaire pour l'instant.</p>
|
||||||
|
</div>
|
||||||
|
<ul th:if="${!#lists.isEmpty(commentaires)}">
|
||||||
|
<li th:each="c : ${commentaires}">
|
||||||
|
<strong th:text="${c.auteur.email}">Auteur</strong> :
|
||||||
|
<span th:text="${c.contenu}"></span>
|
||||||
|
<em>(<span th:text="${c.dateCommentaire}"></span>)</em>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- Formulaire d'ajout de commentaire -->
|
||||||
|
<div th:if="${currentUser}">
|
||||||
|
<h3>Ajouter un commentaire</h3>
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
||||||
|
<textarea name="contenu" rows="3" cols="50"></textarea><br/>
|
||||||
|
<button type="submit">Envoyer</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div th:if="${currentUser == null}">
|
||||||
|
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user