FEAT : Pagination des commentaires / photos

This commit is contained in:
2025-12-02 19:43:29 +01:00
parent 6cb141293c
commit ce5ed0cbe3
115 changed files with 240 additions and 121 deletions

View File

@@ -82,7 +82,8 @@ public class PhotoController {
String contentType = "application/octet-stream"; String contentType = "application/octet-stream";
try { try {
contentType = Files.probeContentType(p); contentType = Files.probeContentType(p);
} catch (Exception ignored) {} } catch (Exception ignored) {
}
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType)) .contentType(MediaType.parseMediaType(contentType))
@@ -92,14 +93,27 @@ public class PhotoController {
} }
@GetMapping("/mes-photos") @GetMapping("/mes-photos")
public String mesPhotos(Model model, Authentication auth) { public String mesPhotos(
@RequestParam(name = "pagePrivees", defaultValue = "0") int pagePrivees,
@RequestParam(name = "pagePubliques", defaultValue = "0") int pagePubliques,
@RequestParam(name = "pagePartagees", defaultValue = "0") int pagePartagees,
Model model,
Authentication auth
) {
String email = auth.getName(); String email = auth.getName();
model.addAttribute("photosPrivees", photoService.listPrivatePhotos(email)); // Chaque liste utilise sa propre pagination
model.addAttribute("photosPubliques", photoService.listPublicPhotos(email)); model.addAttribute("photosPrivees", photoService.listPrivatePhotos(email, pagePrivees, 12));
model.addAttribute("photosPartagees", photoService.listSharedWith(email)); model.addAttribute("photosPubliques", photoService.listPublicPhotos(email, pagePubliques, 12));
model.addAttribute("photosPartagees", photoService.listSharedWith(email, pagePartagees, 12));
// Ajouter les 3 index séparés
model.addAttribute("pagePrivees", pagePrivees);
model.addAttribute("pagePubliques", pagePubliques);
model.addAttribute("pagePartagees", pagePartagees);
return "mes-photos"; return "mes-photos";
} }
@GetMapping("/galerie") @GetMapping("/galerie")
public String galerie(@RequestParam(defaultValue = "0") int page, Model model) { public String galerie(@RequestParam(defaultValue = "0") int page, Model model) {
Page<Photo> photosPage = photoService.listPublic(page, 12); Page<Photo> photosPage = photoService.listPublic(page, 12);
@@ -112,28 +126,28 @@ public class PhotoController {
@GetMapping("/photo/{id}") @GetMapping("/photo/{id}")
@PreAuthorize("@securityService.canAccessPhoto(authentication, #id)") @PreAuthorize("@securityService.canAccessPhoto(authentication, #id)")
public String viewPhoto(@PathVariable Long id, public String viewPhoto(@PathVariable Long id,
@RequestParam(defaultValue = "0") int page,
Model model, Model model,
Authentication auth) { Authentication auth) {
Photo photo = photoRepository.findById(id).orElse(null); Photo photo = photoRepository.findById(id).orElse(null);
if (photo == null) { if (photo == null) {
return "redirect:/galerie"; return "redirect:/galerie";
} }
model.addAttribute("photo", photo); model.addAttribute("photo", photo);
model.addAttribute("commentaires", commentaireService.listByPhoto(id)); // Pagination des commentaires
model.addAttribute("commentairesPage",
// utilisateur connecté (peut être null si visiteur) commentaireService.listByPhoto(id, page, 10));
model.addAttribute("currentPage", page);
// utilisateur connecté (peut être null)
String currentUser = (auth != null ? auth.getName() : null); String currentUser = (auth != null ? auth.getName() : null);
model.addAttribute("currentUser", currentUser); model.addAttribute("currentUser", currentUser);
// Liste des partages // Liste des partages
List<Partage> partages = partageRepository.findByPhoto_Id(id); List<Partage> partages = partageRepository.findByPhoto_Id(id);
model.addAttribute("partages", partages); model.addAttribute("partages", partages);
return "photo-detail"; return "photo-detail";
} }
@PostMapping("/photo/{id}/comment") @PostMapping("/photo/{id}/comment")
public String addComment(@PathVariable Long id, public String addComment(@PathVariable Long id,
@RequestParam String contenu, @RequestParam String contenu,

View File

@@ -1,11 +1,15 @@
package local.epul4a.fotosharing.repository; package local.epul4a.fotosharing.repository;
import local.epul4a.fotosharing.model.Commentaire; import local.epul4a.fotosharing.model.Commentaire;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
public interface CommentaireRepository extends JpaRepository<Commentaire, Long> { public interface CommentaireRepository extends JpaRepository<Commentaire, Long> {
List<Commentaire> findByPhoto_IdOrderByDateCommentaireAsc(Long photoId); List<Commentaire> findByPhoto_IdOrderByDateCommentaireAsc(Long photoId);
Page<Commentaire> findByPhoto_Id(Long photoId, Pageable pageable);
} }

View File

@@ -11,5 +11,16 @@ public interface PhotoRepository extends JpaRepository<Photo, Long> {
List<Photo> findByProprietaire_Email(String email); List<Photo> findByProprietaire_Email(String email);
List<Photo> findByVisibilite(Photo.Visibilite visibilite); List<Photo> findByVisibilite(Photo.Visibilite visibilite);
Page<Photo> findByVisibilite(Photo.Visibilite visibilite, Pageable pageable); Page<Photo> findByVisibilite(Photo.Visibilite visibilite, Pageable pageable);
Page<Photo> findByProprietaire_Email(String email, Pageable pageable);
Page<Photo> findByProprietaire_EmailAndVisibilite(
String email,
Photo.Visibilite visibilite,
Pageable pageable
);
Page<Photo> findByVisibiliteAndProprietaire_Email(
Photo.Visibilite visibilite,
String email,
Pageable pageable
);
} }

View File

@@ -1,9 +1,13 @@
package local.epul4a.fotosharing.service; package local.epul4a.fotosharing.service;
import local.epul4a.fotosharing.model.Commentaire; import local.epul4a.fotosharing.model.Commentaire;
import org.springframework.data.domain.Page;
import java.util.List; import java.util.List;
public interface CommentaireService { public interface CommentaireService {
List<Commentaire> listByPhoto(Long photoId); List<Commentaire> listByPhoto(Long photoId);
void addComment(Long photoId, String email, String contenu); void addComment(Long photoId, String email, String contenu);
Page<Commentaire> listByPhoto(Long photoId, int page, int size);
} }

View File

@@ -17,6 +17,10 @@ public interface PhotoService {
List<Photo> listPublicPhotos(String email); List<Photo> listPublicPhotos(String email);
void unshare(Long photoId, String email); void unshare(Long photoId, String email);
Page<Photo> listPublic(int page, int size); Page<Photo> listPublic(int page, int size);
Page<Photo> listPrivatePhotos(String email, int page, int size);
Page<Photo> listPublicPhotos(String email, int page, int size);
Page<Photo> listSharedWith(String email, int page, int size);

View File

@@ -7,6 +7,9 @@ import local.epul4a.fotosharing.repository.CommentaireRepository;
import local.epul4a.fotosharing.repository.PhotoRepository; import local.epul4a.fotosharing.repository.PhotoRepository;
import local.epul4a.fotosharing.repository.UtilisateurRepository; import local.epul4a.fotosharing.repository.UtilisateurRepository;
import local.epul4a.fotosharing.service.CommentaireService; import local.epul4a.fotosharing.service.CommentaireService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -47,4 +50,10 @@ public class CommentaireServiceImpl implements CommentaireService {
commentaireRepository.save(c); commentaireRepository.save(c);
} }
@Override
public Page<Commentaire> listByPhoto(Long photoId, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return commentaireRepository.findByPhoto_Id(photoId, pageable);
}
} }

View File

@@ -9,6 +9,7 @@ import local.epul4a.fotosharing.repository.UtilisateurRepository;
import local.epul4a.fotosharing.service.PhotoService; import local.epul4a.fotosharing.service.PhotoService;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -115,5 +116,35 @@ public class PhotoServiceImpl implements PhotoService {
return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC, pageable); return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC, pageable);
} }
@Override
public Page<Photo> listPrivatePhotos(String email, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return photoRepository.findByProprietaire_EmailAndVisibilite(
email,
Photo.Visibilite.PRIVATE,
pageable
);
}
@Override
public Page<Photo> listPublicPhotos(String email, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return photoRepository.findByProprietaire_EmailAndVisibilite(
email,
Photo.Visibilite.PUBLIC,
pageable
);
}
@Override
public Page<Photo> listSharedWith(String email, int page, int size) {
List<Partage> partages = partageRepository.findByUtilisateur_Email(email);
List<Photo> photos = partages.stream().map(Partage::getPhoto).toList();
// convertir list en page manuellement
int start = page * size;
int end = Math.min(start + size, photos.size());
List<Photo> sublist = photos.subList(start, end);
return new PageImpl<>(sublist, PageRequest.of(page, size), photos.size());
}
} }

View File

@@ -12,31 +12,51 @@
<p>Vous n'avez pas encore de photos.</p> <p>Vous n'avez pas encore de photos.</p>
</div> </div>
<h2>Mes photos privées</h2> <h2>Mes photos privées</h2>
<ul> <div>
<li th:each="p : ${photosPrivees}"> <a th:each="p : ${photosPrivees.content}"
<a th:href="@{'/photo/' + ${p.id}}" th:href="@{'/photo/' + ${p.id}}">
th:text="${p.nomFichierOriginal}"></a> <img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
<span style="color:red;">[PRIVÉE]</span> </a>
</li> </div>
</ul> <div>
<a th:if="${photosPrivees.hasPrevious()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees - 1}, pagePubliques=${pagePubliques}, pagePartagees=${pagePartagees})}"></a>
<span th:text="'Page ' + (${pagePrivees}+1)"></span>
<a th:if="${photosPrivees.hasNext()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees + 1}, pagePubliques=${pagePubliques}, pagePartagees=${pagePartagees})}"></a>
</div>
<h2>Mes photos publiques</h2> <h2>Mes photos publiques</h2>
<ul> <div>
<li th:each="p : ${photosPubliques}"> <a th:each="p : ${photosPubliques.content}"
<a th:href="@{'/photo/' + ${p.id}}" th:href="@{'/photo/' + ${p.id}}">
th:text="${p.nomFichierOriginal}"></a> <img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
<span style="color:blue;">[PUBLIQUE]</span> </a>
</li> </div>
</ul> <div>
<a th:if="${photosPubliques.hasPrevious()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees}, pagePubliques=${pagePubliques - 1}, pagePartagees=${pagePartagees})}"></a>
<span th:text="'Page ' + (${pagePubliques}+1)"></span>
<a th:if="${photosPubliques.hasNext()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees}, pagePubliques=${pagePubliques + 1}, pagePartagees=${pagePartagees})}"></a>
</div>
<h2>Photos partagées avec moi</h2> <h2>Photos partagées avec moi</h2>
<ul> <div>
<li th:each="p : ${photosPartagees}"> <a th:each="p : ${photosPartagees.content}"
<a th:href="@{'/photo/' + ${p.id}}" th:href="@{'/photo/' + ${p.id}}">
th:text="${p.nomFichierOriginal}"></a> <img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
<span style="color:green;">[SHARED]</span> </a>
</li> </div>
</ul> <div>
<a th:if="${photosPartagees.hasPrevious()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees}, pagePubliques=${pagePubliques}, pagePartagees=${pagePartagees - 1})}"></a>
<span th:text="'Page ' + (${pagePartagees}+1)"></span>
<a th:if="${photosPartagees.hasNext()}"
th:href="@{/mes-photos(pagePrivees=${pagePrivees}, pagePubliques=${pagePubliques}, pagePartagees=${pagePartagees + 1})}"></a>
</div>
<p><a th:href="@{/galerie}">Galerie publique</a></p> <p><a th:href="@{/galerie}">Galerie publique</a></p>

View File

@@ -53,16 +53,20 @@
<!-- Commentaires --> <!-- Commentaires -->
<h2>Commentaires</h2> <h2>Commentaires</h2>
<div th:if="${#lists.isEmpty(commentaires)}"> <div th:each="c : ${commentairesPage.content}">
<p>Aucun commentaire pour l'instant.</p> <p>
</div> <b th:text="${c.auteur.email}"></b>
<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> <span th:text="${c.contenu}"></span>
<em>(<span th:text="${c.dateCommentaire}"></span>)</em> </p>
</li> </div>
</ul> <div>
<a th:if="${commentairesPage.hasPrevious()}"
th:href="@{/photo/{id}(id=${photo.id}, page=${currentPage - 1})}"></a>
<span th:text="'Page ' + (${currentPage}+1)"></span>
<a th:if="${commentairesPage.hasNext()}"
th:href="@{/photo/{id}(id=${photo.id}, page=${currentPage + 1})}"></a>
</div>
<!-- Formulaire d'ajout de commentaire --> <!-- Formulaire d'ajout de commentaire -->
<div th:if="${currentUser}"> <div th:if="${currentUser}">
<h3>Ajouter un commentaire</h3> <h3>Ajouter un commentaire</h3>

View File

@@ -1,17 +0,0 @@
spring.application.name=FotoSharing
# ===============================
# DATABASE
# ===============================
spring.datasource.url=jdbc:mariadb://192.168.124.171:3306/fotoshareDB
spring.datasource.username=ufoto
spring.datasource.password=4AinfoRep-25
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.jpa.show-sql=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML

View File

@@ -1,9 +0,0 @@
<!doctype html>
<html>
<head>
<title>FotoSharing Title!</title>
</head>
<body>
<h1>FotoSharing Title!</h1>
</body>
</html>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"
metadata-complete="false">
<display-name>FotoSharing</display-name>
<!-- Désactiver l'enregistrement automatique du filtre d'erreur -->
<absolute-ordering>
<name>spring_web</name>
</absolute-ordering>
</web-app>

View File

@@ -1,4 +1,7 @@
spring.application.name=FotoSharing spring.application.name=FotoSharing
spring.jmx.enabled=false
management.endpoints.jmx.exposure.exclude=*
# =============================== # ===============================
# DATABASE # DATABASE

Some files were not shown because too many files have changed in this diff Show More