FEAT : ajout de la suppression en cascade d'une photo (suppression de ses commentaires, partage, présence dans des albums, et du fichier /opt/........
This commit is contained in:
@@ -163,7 +163,10 @@ public class PhotoController {
|
||||
|
||||
model.addAttribute("partages",
|
||||
partageService.getPartagesForPhoto(id));
|
||||
|
||||
boolean isOwner = auth != null &&
|
||||
photo.getProprietaire() != null &&
|
||||
auth.getName().equals(photo.getProprietaire().getEmail());
|
||||
model.addAttribute("isOwner", isOwner);
|
||||
return "photo-detail";
|
||||
}
|
||||
|
||||
@@ -230,6 +233,21 @@ public class PhotoController {
|
||||
return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(r);
|
||||
}
|
||||
|
||||
/* ========================== SUPPRESSION PHOTO ========================== */
|
||||
@PostMapping("/photo/{id}/delete")
|
||||
@PreAuthorize("@securityService.canAccessPhoto(authentication, #id)")
|
||||
public String deletePhoto(
|
||||
@PathVariable Long id,
|
||||
Authentication auth) {
|
||||
PhotoDTO p = photoService.getPhotoById(id);
|
||||
if (p == null || !p.getProprietaire().getEmail().equals(auth.getName())) {
|
||||
return "redirect:/mes-photos?error=forbidden";
|
||||
}
|
||||
photoService.deletePhoto(id);
|
||||
return "redirect:/mes-photos?deleted";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -44,6 +44,8 @@ public class Album {
|
||||
private Set<Partage> partages = new HashSet<>();
|
||||
|
||||
|
||||
|
||||
|
||||
public enum Visibilite {
|
||||
PRIVATE,
|
||||
SHARED,
|
||||
|
||||
@@ -35,6 +35,9 @@ public class Photo {
|
||||
@OneToMany(mappedBy = "photo", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private Set<Partage> partages = new HashSet<>();
|
||||
|
||||
@OneToMany(mappedBy = "photo", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private Set<Commentaire> commentaires = new HashSet<>();
|
||||
|
||||
@Column
|
||||
private String uuidThumbnail;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public interface PhotoService {
|
||||
Page<PhotoDTO> listSharedWith(String email, int page, int size);
|
||||
Page<PhotoDTO> listSharedPhotos(String email, int page, int size);
|
||||
List<PhotoDTO> listAllPhotosOfUser(String email);
|
||||
void deletePhoto(Long id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package local.epul4a.fotosharing.service.impl;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import local.epul4a.fotosharing.dto.PhotoDTO;
|
||||
import local.epul4a.fotosharing.mapper.PhotoMapper;
|
||||
import local.epul4a.fotosharing.model.Album;
|
||||
import local.epul4a.fotosharing.model.Partage;
|
||||
import local.epul4a.fotosharing.model.Photo;
|
||||
import local.epul4a.fotosharing.model.Utilisateur;
|
||||
@@ -185,4 +187,28 @@ public class PhotoServiceImpl implements PhotoService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
//============= DELETE PHOTO =============================
|
||||
@Override
|
||||
@Transactional
|
||||
public void deletePhoto(Long id) {
|
||||
Photo photo = photoRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Photo introuvable"));
|
||||
//Retirer la photo de tous ses albums
|
||||
for (Album album : photo.getAlbums()) {
|
||||
album.getPhotos().remove(photo);
|
||||
}
|
||||
//Supprimer les fichiers (original + miniature)
|
||||
try {
|
||||
Path original = Paths.get(uploadDir).resolve(photo.getUuidFichier());
|
||||
Path thumb = Paths.get(uploadDir).resolve(photo.getUuidThumbnail());
|
||||
Files.deleteIfExists(original);
|
||||
Files.deleteIfExists(thumb);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Erreur suppression fichiers", ex);
|
||||
}
|
||||
//Supprimer la photo en base & supprime aussi commentaires + partages via cascade
|
||||
photoRepository.delete(photo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -29,6 +29,17 @@
|
||||
<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>
|
||||
<!-- Suppression de la photo par le propriétaire -->
|
||||
<div th:if="${isOwner}">
|
||||
<form th:action="@{'/photo/' + ${photo.id} + '/delete'}" method="post"
|
||||
onsubmit="return confirm('Supprimer définitivement cette photo ?');">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
||||
<button type="submit" style="color:red; margin-bottom:20px;">
|
||||
Supprimer la photo
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Partage de la photo -->
|
||||
<!-- Formulaire gestion visible uniquement en ADMIN ou PROPRIÉTAIRE -->
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -29,6 +29,17 @@
|
||||
<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>
|
||||
<!-- Suppression de la photo par le propriétaire -->
|
||||
<div th:if="${isOwner}">
|
||||
<form th:action="@{'/photo/' + ${photo.id} + '/delete'}" method="post"
|
||||
onsubmit="return confirm('Supprimer définitivement cette photo ?');">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
||||
<button type="submit" style="color:red; margin-bottom:20px;">
|
||||
Supprimer la photo
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Partage de la photo -->
|
||||
<!-- Formulaire gestion visible uniquement en ADMIN ou PROPRIÉTAIRE -->
|
||||
|
||||
Reference in New Issue
Block a user