FEAT : ajout partage simple
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
package local.epul4a.fotosharing.controller;
|
package local.epul4a.fotosharing.controller;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Partage;
|
||||||
import local.epul4a.fotosharing.model.Photo;
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
import local.epul4a.fotosharing.model.Utilisateur;
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.PartageRepository;
|
||||||
import local.epul4a.fotosharing.repository.PhotoRepository;
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.UtilisateurRepository;
|
||||||
import local.epul4a.fotosharing.security.CustomUserDetails;
|
import local.epul4a.fotosharing.security.CustomUserDetails;
|
||||||
import local.epul4a.fotosharing.service.CommentaireService;
|
import local.epul4a.fotosharing.service.CommentaireService;
|
||||||
import local.epul4a.fotosharing.service.PhotoService;
|
import local.epul4a.fotosharing.service.PhotoService;
|
||||||
@@ -11,6 +14,7 @@ import org.springframework.core.io.PathResource;
|
|||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
@@ -20,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class PhotoController {
|
public class PhotoController {
|
||||||
@@ -27,11 +32,15 @@ public class PhotoController {
|
|||||||
private final PhotoService photoService;
|
private final PhotoService photoService;
|
||||||
private final PhotoRepository photoRepository;
|
private final PhotoRepository photoRepository;
|
||||||
private final CommentaireService commentaireService;
|
private final CommentaireService commentaireService;
|
||||||
|
private final UtilisateurRepository utilisateurRepository;
|
||||||
|
private final PartageRepository partageRepository;
|
||||||
|
|
||||||
public PhotoController(PhotoService photoService, PhotoRepository photoRepository, CommentaireService commentaireService) {
|
public PhotoController(PhotoService photoService, PhotoRepository photoRepository, CommentaireService commentaireService, UtilisateurRepository utilisateurRepository, PartageRepository partageRepository) {
|
||||||
this.photoService = photoService;
|
this.photoService = photoService;
|
||||||
this.photoRepository = photoRepository;
|
this.photoRepository = photoRepository;
|
||||||
this.commentaireService = commentaireService;
|
this.commentaireService = commentaireService;
|
||||||
|
this.utilisateurRepository = utilisateurRepository;
|
||||||
|
this.partageRepository = partageRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/upload")
|
@GetMapping("/upload")
|
||||||
@@ -84,7 +93,13 @@ public class PhotoController {
|
|||||||
@GetMapping("/mes-photos")
|
@GetMapping("/mes-photos")
|
||||||
public String mesPhotos(Model model, Authentication authentication) {
|
public String mesPhotos(Model model, Authentication authentication) {
|
||||||
String email = authentication.getName();
|
String email = authentication.getName();
|
||||||
model.addAttribute("photos", photoService.listByOwner(email));
|
// photos que je possède
|
||||||
|
List<Photo> mesPhotos = photoService.listByOwner(email);
|
||||||
|
// photos partagées avec moi
|
||||||
|
List<Photo> photosPartagees = photoService.listSharedWith(email);
|
||||||
|
model.addAttribute("mesPhotos", mesPhotos);
|
||||||
|
model.addAttribute("photosPartagees", photosPartagees);
|
||||||
|
|
||||||
return "mes-photos";
|
return "mes-photos";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +110,7 @@ public class PhotoController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/photo/{id}")
|
@GetMapping("/photo/{id}")
|
||||||
|
@PreAuthorize("@securityService.canAccessPhoto(authentication, #id)")
|
||||||
public String viewPhoto(@PathVariable Long id,
|
public String viewPhoto(@PathVariable Long id,
|
||||||
Model model,
|
Model model,
|
||||||
Authentication auth) {
|
Authentication auth) {
|
||||||
@@ -126,5 +142,30 @@ public class PhotoController {
|
|||||||
return "redirect:/photo/" + id;
|
return "redirect:/photo/" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/photo/{id}/share")
|
||||||
|
@PreAuthorize("@securityService.canAccessPhoto(authentication, #id)")
|
||||||
|
public String share(@PathVariable Long id,
|
||||||
|
@RequestParam String email,
|
||||||
|
Authentication auth) {
|
||||||
|
// Vérifier que c'est le propriétaire
|
||||||
|
Photo photo = photoRepository.findById(id).orElse(null);
|
||||||
|
if (photo == null) return "redirect:/galerie";
|
||||||
|
if (!photo.getProprietaire().getEmail().equals(auth.getName())) {
|
||||||
|
return "redirect:/photo/" + id + "?error=notowner";
|
||||||
|
}
|
||||||
|
// Trouver utilisateur
|
||||||
|
Utilisateur user = utilisateurRepository.findByEmail(email).orElse(null);
|
||||||
|
if (user == null) {
|
||||||
|
return "redirect:/photo/" + id + "?error=usernotfound";
|
||||||
|
}
|
||||||
|
// Ajouter partage
|
||||||
|
Partage p = new Partage();
|
||||||
|
p.setPhoto(photo);
|
||||||
|
p.setUtilisateur(user);
|
||||||
|
partageRepository.save(p);
|
||||||
|
return "redirect:/photo/" + id + "?shared=ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package local.epul4a.fotosharing.repository;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Partage;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface PartageRepository extends JpaRepository<Partage, Long> {
|
||||||
|
// liste des partages pour une photo
|
||||||
|
List<Partage> findByPhoto_Id(Long photoId);
|
||||||
|
// vérifier si un utilisateur a accès partagé
|
||||||
|
boolean existsByPhoto_IdAndUtilisateur_Email(Long photoId, String email);
|
||||||
|
List<Partage> findByUtilisateur_Email(String email);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,29 +1,47 @@
|
|||||||
package local.epul4a.fotosharing.security;
|
package local.epul4a.fotosharing.security;
|
||||||
|
|
||||||
import local.epul4a.fotosharing.model.Photo;
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
|
import local.epul4a.fotosharing.repository.PartageRepository;
|
||||||
import local.epul4a.fotosharing.repository.PhotoRepository;
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.naming.ldap.PagedResultsControl;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
|
||||||
@Service("securityService")
|
@Service("securityService")
|
||||||
public class SecurityService {
|
public class SecurityService {
|
||||||
|
|
||||||
private final PhotoRepository photoRepository;
|
private final PhotoRepository photoRepository;
|
||||||
|
private final PartageRepository partageRepository;
|
||||||
|
|
||||||
public SecurityService(PhotoRepository photoRepository) {
|
public SecurityService(PhotoRepository photoRepository, PartageRepository partageRepository) {
|
||||||
this.photoRepository = photoRepository;
|
this.photoRepository = photoRepository;
|
||||||
|
this.partageRepository = partageRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canAccessPhoto(org.springframework.security.core.Authentication authentication, Long photoId) {
|
public boolean canAccessPhoto(Authentication authentication, Long photoId) {
|
||||||
if (authentication == null || !authentication.isAuthenticated()) return false;
|
Photo photo = photoRepository.findById(photoId).orElse(null);
|
||||||
String username = authentication.getName(); // email
|
if (photo == null) return false;
|
||||||
Optional<Photo> p = photoRepository.findById(photoId);
|
// PUBLIC → accès total
|
||||||
if (p.isEmpty()) return false;
|
if (photo.getVisibilite() == Photo.Visibilite.PUBLIC) {
|
||||||
Photo photo = p.get();
|
return true;
|
||||||
if (photo.getVisibilite() == Photo.Visibilite.PUBLIC) return true;
|
}
|
||||||
if (photo.getProprietaire() != null && photo.getProprietaire().getEmail().equals(username)) return true;
|
// Pas connecté → rejeter tout sauf PUBLIC
|
||||||
// TODO: vérifier table partage
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String email = authentication.getName();
|
||||||
|
// Propriétaire → OK
|
||||||
|
if (photo.getProprietaire().getEmail().equals(email)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// SHARED → vérifier dans la table PARTAGE
|
||||||
|
if (photo.getVisibilite() == Photo.Visibilite.SHARED) {
|
||||||
|
return partageRepository.existsByPhoto_IdAndUtilisateur_Email(photoId, email);
|
||||||
|
}
|
||||||
|
// PRIVATE par défaut → refus
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,7 @@ public interface PhotoService {
|
|||||||
Path loadAsPath(String uuidFile);
|
Path loadAsPath(String uuidFile);
|
||||||
List<Photo> listByOwner(String email);
|
List<Photo> listByOwner(String email);
|
||||||
List<Photo> listPublicPhotos();
|
List<Photo> listPublicPhotos();
|
||||||
|
List<Photo> listSharedWith(String email);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package local.epul4a.fotosharing.service.impl;
|
package local.epul4a.fotosharing.service.impl;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Partage;
|
||||||
import local.epul4a.fotosharing.model.Photo;
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
import local.epul4a.fotosharing.model.Utilisateur;
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.PartageRepository;
|
||||||
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.PhotoService;
|
import local.epul4a.fotosharing.service.PhotoService;
|
||||||
@@ -24,10 +26,12 @@ public class PhotoServiceImpl implements PhotoService {
|
|||||||
|
|
||||||
private final PhotoRepository photoRepository;
|
private final PhotoRepository photoRepository;
|
||||||
private final UtilisateurRepository utilisateurRepository;
|
private final UtilisateurRepository utilisateurRepository;
|
||||||
|
private final PartageRepository partageRepository;
|
||||||
|
|
||||||
public PhotoServiceImpl(PhotoRepository photoRepository, UtilisateurRepository utilisateurRepository) {
|
public PhotoServiceImpl(PhotoRepository photoRepository, UtilisateurRepository utilisateurRepository, PartageRepository partageRepository) {
|
||||||
this.photoRepository = photoRepository;
|
this.photoRepository = photoRepository;
|
||||||
this.utilisateurRepository = utilisateurRepository;
|
this.utilisateurRepository = utilisateurRepository;
|
||||||
|
this.partageRepository = partageRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,4 +73,14 @@ public class PhotoServiceImpl implements PhotoService {
|
|||||||
public List<Photo> listPublicPhotos() {
|
public List<Photo> listPublicPhotos() {
|
||||||
return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC);
|
return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Photo> listSharedWith(String email) {
|
||||||
|
List<Partage> partages = partageRepository.findByUtilisateur_Email(email);
|
||||||
|
|
||||||
|
return partages.stream()
|
||||||
|
.map(Partage::getPhoto)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,23 +5,34 @@
|
|||||||
<title>Mes photos</title>
|
<title>Mes photos</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Mes photos</h1>
|
<h2>Mes photos</h2>
|
||||||
|
|
||||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||||
<p><a th:href="@{/}">Retour accueil</a></p>
|
<p><a th:href="@{/}">Retour accueil</a></p>
|
||||||
|
<div th:if="${#lists.isEmpty(mesPhotos)}">
|
||||||
<div th:if="${#lists.isEmpty(photos)}">
|
|
||||||
<p>Vous n'avez pas encore de photos.</p>
|
<p>Vous n'avez pas encore de photos.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<ul>
|
||||||
<ul th:if="${!#lists.isEmpty(photos)}">
|
<li th:each="p : ${mesPhotos}">
|
||||||
<li th:each="p : ${photos}">
|
<span th:text="${p.nomFichierOriginal}"></span>
|
||||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h2>Photos partagées avec moi</h2>
|
||||||
|
<div th:if="${#lists.isEmpty(photosPartagees)}">
|
||||||
|
<p>Aucune photo partagée.</p>
|
||||||
|
</div>
|
||||||
|
<ul th:if="${!#lists.isEmpty(photosPartagees)}">
|
||||||
|
<li th:each="p : ${photosPartagees}">
|
||||||
|
<span th:text="${p.nomFichierOriginal}"></span>
|
||||||
|
<span style="color: green; font-weight: bold;">[SHARED]</span>
|
||||||
|
—
|
||||||
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<p><a th:href="@{/galerie}">Galerie publique</a></p>
|
<p><a th:href="@{/galerie}">Galerie publique</a></p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -29,6 +29,20 @@
|
|||||||
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<!-- Partage de la photo -->
|
||||||
|
<h2>Partager la photo</h2>
|
||||||
|
<div th:if="${currentUser == photo.proprietaire.email}">
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
||||||
|
<label>Email de l'utilisateur :</label>
|
||||||
|
<input type="email" name="email" required />
|
||||||
|
<button type="submit">Partager</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div th:if="${currentUser != photo.proprietaire.email}">
|
||||||
|
<em>Seul le propriétaire peut partager cette photo.</em>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Commentaires -->
|
<!-- Commentaires -->
|
||||||
<h2>Commentaires</h2>
|
<h2>Commentaires</h2>
|
||||||
<div th:if="${#lists.isEmpty(commentaires)}">
|
<div th:if="${#lists.isEmpty(commentaires)}">
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,23 +5,34 @@
|
|||||||
<title>Mes photos</title>
|
<title>Mes photos</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Mes photos</h1>
|
<h2>Mes photos</h2>
|
||||||
|
|
||||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||||
<p><a th:href="@{/}">Retour accueil</a></p>
|
<p><a th:href="@{/}">Retour accueil</a></p>
|
||||||
|
<div th:if="${#lists.isEmpty(mesPhotos)}">
|
||||||
<div th:if="${#lists.isEmpty(photos)}">
|
|
||||||
<p>Vous n'avez pas encore de photos.</p>
|
<p>Vous n'avez pas encore de photos.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<ul>
|
||||||
<ul th:if="${!#lists.isEmpty(photos)}">
|
<li th:each="p : ${mesPhotos}">
|
||||||
<li th:each="p : ${photos}">
|
<span th:text="${p.nomFichierOriginal}"></span>
|
||||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
|
||||||
—
|
—
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h2>Photos partagées avec moi</h2>
|
||||||
|
<div th:if="${#lists.isEmpty(photosPartagees)}">
|
||||||
|
<p>Aucune photo partagée.</p>
|
||||||
|
</div>
|
||||||
|
<ul th:if="${!#lists.isEmpty(photosPartagees)}">
|
||||||
|
<li th:each="p : ${photosPartagees}">
|
||||||
|
<span th:text="${p.nomFichierOriginal}"></span>
|
||||||
|
<span style="color: green; font-weight: bold;">[SHARED]</span>
|
||||||
|
—
|
||||||
|
<a th:href="@{'/photo/' + ${p.id}}">Voir</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<p><a th:href="@{/galerie}">Galerie publique</a></p>
|
<p><a th:href="@{/galerie}">Galerie publique</a></p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -29,6 +29,20 @@
|
|||||||
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
<li><strong>Propriétaire :</strong> <span th:text="${photo.proprietaire.email}"></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<!-- Partage de la photo -->
|
||||||
|
<h2>Partager la photo</h2>
|
||||||
|
<div th:if="${currentUser == photo.proprietaire.email}">
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
||||||
|
<label>Email de l'utilisateur :</label>
|
||||||
|
<input type="email" name="email" required />
|
||||||
|
<button type="submit">Partager</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div th:if="${currentUser != photo.proprietaire.email}">
|
||||||
|
<em>Seul le propriétaire peut partager cette photo.</em>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Commentaires -->
|
<!-- Commentaires -->
|
||||||
<h2>Commentaires</h2>
|
<h2>Commentaires</h2>
|
||||||
<div th:if="${#lists.isEmpty(commentaires)}">
|
<div th:if="${#lists.isEmpty(commentaires)}">
|
||||||
|
|||||||
Reference in New Issue
Block a user