diff --git a/src/main/java/local/epul4a/fotosharing/controller/AlbumController.java b/src/main/java/local/epul4a/fotosharing/controller/AlbumController.java new file mode 100644 index 0000000..ad47d31 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/controller/AlbumController.java @@ -0,0 +1,169 @@ +package local.epul4a.fotosharing.controller; + +import local.epul4a.fotosharing.dto.AlbumDTO; +import local.epul4a.fotosharing.dto.PhotoDTO; +import local.epul4a.fotosharing.service.AlbumService; +import local.epul4a.fotosharing.service.PartageService; +import local.epul4a.fotosharing.service.PhotoService; +import org.springframework.data.domain.Page; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Controller +public class AlbumController { + + private final AlbumService albumService; + private final PhotoService photoService; + private final PartageService partageService; + public AlbumController(AlbumService albumService,PhotoService photoService,PartageService partageService) { + this.albumService = albumService; + this.photoService = photoService; + this.partageService = partageService; + } + + /* ============================ MES ALBUMS ============================ */ + @GetMapping("/mes-albums") + public String mesAlbums( + @RequestParam(defaultValue = "0") int page, + Authentication auth, + Model model + ) { + String email = auth.getName(); + Page albums = albumService.listMyAlbums(email, page, 10); + List sharedAlbums = albumService.listAlbumsSharedWithMe(email); + model.addAttribute("albums", albums); + model.addAttribute("currentPage", page); + model.addAttribute("sharedAlbums", sharedAlbums); + return "mes-albums"; + } + + + /* ============================ CREATION ALBUM ============================ */ + @PostMapping("/albums/create") + public String createAlbum( + @RequestParam String nom, + @RequestParam(required = false) String description, + @RequestParam(defaultValue = "PRIVATE") String visibilite, + Authentication auth + ) { + albumService.createAlbum(nom, description, visibilite, auth.getName()); + return "redirect:/mes-albums"; + } + + + /* ============================ DETAIL ALBUM ============================ */ + @GetMapping("/album/{id}") + public String viewAlbum( + @PathVariable Long id, + Authentication auth, + Model model + ) { + String email = auth.getName(); + AlbumDTO album = albumService.getAlbum(id); + if (album == null) + return "redirect:/mes-albums"; + model.addAttribute("album", album); + model.addAttribute("myPhotos", photoService.listAllPhotosOfUser(email)); + model.addAttribute("partages", partageService.getAlbumPartages(id)); + boolean canAdmin = partageService.canAdminAlbum(id, email); + model.addAttribute("canAdmin", canAdmin); + return "album-detail"; + } + + + /* ============================ AJOUT PHOTO ============================ */ + @PostMapping("/album/{id}/add") + public String addPhoto( + @PathVariable Long id, + @RequestParam Long photoId, + Authentication auth + ) { + try { + albumService.addPhoto(id, photoId, auth.getName()); + return "redirect:/album/" + id + "?added=ok"; + } catch (RuntimeException ex) { + return "redirect:/album/" + id + "?error=" + URLEncoder.encode(ex.getMessage(), StandardCharsets.UTF_8); + } + } + + + /* ============================ RETIRER PHOTO ============================ */ + @GetMapping("/album/{id}/remove/{photoId}") + public String removePhoto( + @PathVariable Long id, + @PathVariable Long photoId, + Authentication auth + ) { + albumService.removePhoto(id, photoId, auth.getName()); + return "redirect:/album/" + id; + } + + /* ============================ SUPPRESSION ALBUM ============================ */ + @GetMapping("/album/{id}/delete") + public String deleteAlbum( + @PathVariable Long id, + Authentication auth + ) { + albumService.deleteAlbum(id, auth.getName()); + return "redirect:/mes-albums"; + } + + /* ============================ PARTAGE ALBUM ============================ */ + @PostMapping("/album/{id}/share") + public String shareAlbum( + @PathVariable Long id, + @RequestParam String email, + @RequestParam String permission, + Authentication auth + ) { + try { + albumService.shareAlbum(id, email, permission, auth.getName()); + return "redirect:/album/" + id + "?shared=ok"; + } catch (Exception e) { + return "redirect:/album/" + id + "?error=" + e.getMessage(); + } + } + + + /* ============================ SUPPRIMER PARTAGE ALBUM ============================ */ + @GetMapping("/album/{id}/share/remove/{email}") + public String removeShareAlbum( + @PathVariable Long id, + @PathVariable String email, + Authentication auth + ) { + albumService.removeAlbumShare(id, email, auth.getName()); + return "redirect:/album/" + id + "?removed=ok"; + } + + /* ============================ MAJ PARTAGE ALBUM ============================ */ + @PostMapping("/album/{id}/share/update") + public String updateAlbumShare( + @PathVariable Long id, + @RequestParam String email, + @RequestParam String permission, + Authentication auth + ) { + albumService.updateAlbumPermission(id, email, permission, auth.getName()); + return "redirect:/album/" + id; + } + + /* ============================ SUPPRIMER PARTAGE ALBUM ============================ */ + @GetMapping("/album/{id}/unshare/{email}") + public String unshareAlbum( + @PathVariable Long id, + @PathVariable String email, + Authentication auth + ) { + albumService.removeAlbumShare(id, email, auth.getName()); + return "redirect:/album/" + id; + } + + +} diff --git a/src/main/java/local/epul4a/fotosharing/dto/AlbumDTO.java b/src/main/java/local/epul4a/fotosharing/dto/AlbumDTO.java new file mode 100644 index 0000000..3135fbe --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/dto/AlbumDTO.java @@ -0,0 +1,20 @@ +package local.epul4a.fotosharing.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.List; + +@Getter +@Setter +public class AlbumDTO { + private Long id; + private String nom; + private String description; + private String visibilite; + private LocalDateTime dateCreation; + private UtilisateurDTO proprietaire; + // Liste des photos pas les IDs pour éviter les boucles + private List photos; +} diff --git a/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java b/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java index c4defd2..fac7fe5 100644 --- a/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java +++ b/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java @@ -10,4 +10,8 @@ public class PartageDTO { private UtilisateurDTO utilisateur; private String permission; // READ / COMMENT / ADMIN private PhotoDTO photo; + + public String getUtilisateurEmail() { + return utilisateur != null ? utilisateur.getEmail() : null; + } } diff --git a/src/main/java/local/epul4a/fotosharing/mapper/AlbumMapper.java b/src/main/java/local/epul4a/fotosharing/mapper/AlbumMapper.java new file mode 100644 index 0000000..c6151fd --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/mapper/AlbumMapper.java @@ -0,0 +1,27 @@ +package local.epul4a.fotosharing.mapper; + +import local.epul4a.fotosharing.dto.AlbumDTO; +import local.epul4a.fotosharing.dto.PhotoDTO; +import local.epul4a.fotosharing.model.Album; + +import java.util.stream.Collectors; + +public class AlbumMapper { + public static AlbumDTO toDTO(Album album) { + if (album == null) return null; + AlbumDTO dto = new AlbumDTO(); + dto.setId(album.getId()); + dto.setNom(album.getNom()); + dto.setDescription(album.getDescription()); + dto.setVisibilite(album.getVisibilite().name()); + dto.setDateCreation(album.getDateCreation()); + dto.setProprietaire(UtilisateurMapper.toDTO(album.getProprietaire())); + dto.setPhotos( + album.getPhotos() + .stream() + .map(PhotoMapper::toDTO) + .collect(Collectors.toList()) + ); + return dto; + } +} diff --git a/src/main/java/local/epul4a/fotosharing/model/Album.java b/src/main/java/local/epul4a/fotosharing/model/Album.java new file mode 100644 index 0000000..66a0c73 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/model/Album.java @@ -0,0 +1,52 @@ +package local.epul4a.fotosharing.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Getter +@Setter +public class Album { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String nom; + + @Column(length = 1000) + private String description; + + @ManyToOne(optional = false) + private Utilisateur proprietaire; + + private LocalDateTime dateCreation; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Visibilite visibilite; + + @ManyToMany + @JoinTable( + name = "album_photo", + joinColumns = @JoinColumn(name = "album_id"), + inverseJoinColumns = @JoinColumn(name = "photo_id") + ) + private Set photos = new HashSet<>(); + + @OneToMany(mappedBy = "album", cascade = CascadeType.ALL, orphanRemoval = true) + private Set partages = new HashSet<>(); + + + public enum Visibilite { + PRIVATE, + SHARED, + PUBLIC + } +} diff --git a/src/main/java/local/epul4a/fotosharing/model/Partage.java b/src/main/java/local/epul4a/fotosharing/model/Partage.java index 0e564eb..e9a554a 100644 --- a/src/main/java/local/epul4a/fotosharing/model/Partage.java +++ b/src/main/java/local/epul4a/fotosharing/model/Partage.java @@ -8,25 +8,25 @@ import lombok.Setter; @Getter @Setter public class Partage { - public enum Permission { - READ, - COMMENT, - ADMIN - } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne - @JoinColumn(name = "id_photo") - private Photo photo; - - @ManyToOne - @JoinColumn(name = "id_utilisateur") private Utilisateur utilisateur; @Enumerated(EnumType.STRING) - private Permission permission = Permission.READ; + private Permission permission; + @ManyToOne + private Photo photo; // nullable si partage d’album + + @ManyToOne + private Album album; // nullable si partage de photo + + public enum Permission { + READ, COMMENT, ADMIN + } } + diff --git a/src/main/java/local/epul4a/fotosharing/model/Photo.java b/src/main/java/local/epul4a/fotosharing/model/Photo.java index 5871074..e1ca2ab 100644 --- a/src/main/java/local/epul4a/fotosharing/model/Photo.java +++ b/src/main/java/local/epul4a/fotosharing/model/Photo.java @@ -5,7 +5,8 @@ import lombok.Getter; import lombok.Setter; import java.time.LocalDateTime; -import java.util.List; +import java.util.HashSet; +import java.util.Set; @Entity @Getter @@ -28,5 +29,9 @@ public class Photo { @JoinColumn(name = "id_utilisateur") private Utilisateur proprietaire; - // getters & setters + @ManyToMany(mappedBy = "photos") + private Set albums = new HashSet<>(); + + @OneToMany(mappedBy = "photo", cascade = CascadeType.ALL, orphanRemoval = true) + private Set partages = new HashSet<>(); } diff --git a/src/main/java/local/epul4a/fotosharing/repository/AlbumRepository.java b/src/main/java/local/epul4a/fotosharing/repository/AlbumRepository.java new file mode 100644 index 0000000..436dc52 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/repository/AlbumRepository.java @@ -0,0 +1,18 @@ +package local.epul4a.fotosharing.repository; + +import local.epul4a.fotosharing.model.Album; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface AlbumRepository extends JpaRepository { + // Albums dont je suis propriétaire + List findByProprietaire_Email(String email); + Page findByProprietaire_Email(String email, Pageable pageable); + // Albums publics + Page findByVisibilite(Album.Visibilite visibilite, Pageable pageable); + List findByPartages_Utilisateur_Email(String email); + +} diff --git a/src/main/java/local/epul4a/fotosharing/repository/PartageRepository.java b/src/main/java/local/epul4a/fotosharing/repository/PartageRepository.java index 215ed96..8fdc085 100644 --- a/src/main/java/local/epul4a/fotosharing/repository/PartageRepository.java +++ b/src/main/java/local/epul4a/fotosharing/repository/PartageRepository.java @@ -7,10 +7,16 @@ import java.util.List; import java.util.Optional; public interface PartageRepository extends JpaRepository { - + // PHOTO List findByPhoto_Id(Long photoId); boolean existsByPhoto_IdAndUtilisateur_Email(Long photoId, String email); + Partage findByPhoto_IdAndUtilisateur_Email(Long photoId, String email); + // ALBUM + List findByAlbum_Id(Long albumId); + boolean existsByAlbum_IdAndUtilisateur_Email(Long albumId, String email); + Partage findByAlbum_IdAndUtilisateur_Email(Long albumId, String email); List findByUtilisateur_Email(String email); - Optional findByPhoto_IdAndUtilisateur_Email(Long photoId, String email); int countByPhoto_Id(Long photoId); + } + diff --git a/src/main/java/local/epul4a/fotosharing/service/AlbumService.java b/src/main/java/local/epul4a/fotosharing/service/AlbumService.java new file mode 100644 index 0000000..66f6504 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/AlbumService.java @@ -0,0 +1,24 @@ +package local.epul4a.fotosharing.service; + +import local.epul4a.fotosharing.dto.AlbumDTO; +import local.epul4a.fotosharing.dto.PartageDTO; +import org.springframework.data.domain.Page; + +import java.util.List; + +public interface AlbumService { + AlbumDTO createAlbum(String nom, String description, String visibilite, String ownerEmail); + Page listMyAlbums(String email, int page, int size); + Page listPublicAlbums(int page, int size); + AlbumDTO getAlbum(Long id); + void addPhoto(Long albumId, Long photoId, String ownerEmail); + void removePhoto(Long albumId, Long photoId, String ownerEmail); + void deleteAlbum(Long albumId, String ownerEmail); + void shareAlbum(Long albumId, String targetEmail, String permission, String ownerEmail); + void updateAlbumPermission(Long albumId, String targetEmail, String permission, String ownerEmail); + void removeAlbumShare(Long albumId, String targetEmail, String ownerEmail); + List getAlbumPartages(Long albumId); + List listAlbumsSharedWithMe(String email); + + +} diff --git a/src/main/java/local/epul4a/fotosharing/service/PartageService.java b/src/main/java/local/epul4a/fotosharing/service/PartageService.java index 640cee8..2ae3b8c 100644 --- a/src/main/java/local/epul4a/fotosharing/service/PartageService.java +++ b/src/main/java/local/epul4a/fotosharing/service/PartageService.java @@ -15,5 +15,13 @@ public interface PartageService { boolean canAdmin(Long photoId, String email); void updatePermission(Long photoId, String targetEmail, String newPermission, String ownerEmail); int countShares(Long photoId); + void shareAlbum(Long albumId, String targetEmail, String permission, String ownerEmail); + void updateAlbumPermission(Long albumId, String targetEmail, String newPermission, String ownerEmail); + boolean canViewAlbum(Long albumId, String email); + boolean canCommentAlbum(Long albumId, String email); + boolean canAdminAlbum(Long albumId, String email); + List getAlbumPartages(Long albumId); + void removeAlbumShare(Long albumId, String targetEmail, String ownerEmail); + } diff --git a/src/main/java/local/epul4a/fotosharing/service/PhotoService.java b/src/main/java/local/epul4a/fotosharing/service/PhotoService.java index 5a9b8cf..16dfc55 100644 --- a/src/main/java/local/epul4a/fotosharing/service/PhotoService.java +++ b/src/main/java/local/epul4a/fotosharing/service/PhotoService.java @@ -18,6 +18,8 @@ public interface PhotoService { Page listPublicPhotos(String email, int page, int size); Page listSharedWith(String email, int page, int size); Page listSharedPhotos(String email, int page, int size); + List listAllPhotosOfUser(String email); + diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.java new file mode 100644 index 0000000..7e03ee6 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.java @@ -0,0 +1,209 @@ +package local.epul4a.fotosharing.service.impl; + +import local.epul4a.fotosharing.dto.AlbumDTO; +import local.epul4a.fotosharing.mapper.AlbumMapper; +import local.epul4a.fotosharing.model.Album; +import local.epul4a.fotosharing.model.Partage; +import local.epul4a.fotosharing.model.Photo; +import local.epul4a.fotosharing.model.Utilisateur; +import local.epul4a.fotosharing.repository.AlbumRepository; +import local.epul4a.fotosharing.repository.PartageRepository; +import local.epul4a.fotosharing.repository.PhotoRepository; +import local.epul4a.fotosharing.repository.UtilisateurRepository; +import local.epul4a.fotosharing.service.AlbumService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import local.epul4a.fotosharing.service.PartageService; +import local.epul4a.fotosharing.dto.PartageDTO; +import java.util.List; + + +import java.time.LocalDateTime; + +@Service +public class AlbumServiceImpl implements AlbumService { + private final AlbumRepository albumRepository; + private final UtilisateurRepository utilisateurRepository; + private final PhotoRepository photoRepository; + private final PartageService partageService; + private final PartageRepository partageRepository; + + + + public AlbumServiceImpl( + AlbumRepository albumRepository, + UtilisateurRepository utilisateurRepository, + PhotoRepository photoRepository, + PartageService partageService, + PartageRepository partageRepository + ) { + this.albumRepository = albumRepository; + this.utilisateurRepository = utilisateurRepository; + this.photoRepository = photoRepository; + this.partageService = partageService; + this.partageRepository = partageRepository; + } + + + @Override + public AlbumDTO createAlbum(String nom, String description, String visibilite, String ownerEmail) { + Utilisateur user = utilisateurRepository.findByEmail(ownerEmail) + .orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); + Album album = new Album(); + album.setNom(nom); + album.setDescription(description); + album.setVisibilite(Album.Visibilite.valueOf(visibilite)); + album.setProprietaire(user); + album.setDateCreation(LocalDateTime.now()); + return AlbumMapper.toDTO(albumRepository.save(album)); + } + + @Override + public Page listMyAlbums(String email, int page, int size) { + return albumRepository.findByProprietaire_Email(email, PageRequest.of(page, size)) + .map(AlbumMapper::toDTO); + } + + @Override + public Page listPublicAlbums(int page, int size) { + return albumRepository.findByVisibilite(Album.Visibilite.PUBLIC, PageRequest.of(page, size)) + .map(AlbumMapper::toDTO); + } + + @Override + public AlbumDTO getAlbum(Long id) { + return albumRepository.findById(id) + .map(AlbumMapper::toDTO) + .orElse(null); + } + + @Override + public void addPhoto(Long albumId, Long photoId, String requesterEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + //Propriétaire + boolean isOwner = album.getProprietaire().getEmail().equals(requesterEmail); + //admin du partage + boolean isAdmin = album.getPartages().stream() + .anyMatch(p -> + p.getUtilisateur().getEmail().equals(requesterEmail) + && p.getPermission() == Partage.Permission.ADMIN + ); + if (!isOwner && !isAdmin) + throw new RuntimeException("Vous n’avez pas les droits pour modifier cet album"); + Photo photo = photoRepository.findById(photoId) + .orElseThrow(() -> new RuntimeException("Photo introuvable")); + //Protection anti-doublons + boolean exists = album.getPhotos() + .stream() + .anyMatch(p -> p.getId().equals(photoId)); + if (exists) + throw new RuntimeException("Cette photo est déjà dans cet album"); + album.getPhotos().add(photo); + albumRepository.save(album); + // Synchroniser les partages sur la photo pour les utilisateurs de l'album + album.getPartages().forEach(p -> { + // On vérifie si l'utilisateur n'a PAS déjà un partage sur cette photo + boolean existeDeja = photo.getPartages().stream() + .anyMatch(pp -> pp.getUtilisateur().getEmail().equals(p.getUtilisateur().getEmail())); + + if (!existeDeja) { + // On crée un partage photo identique à l'autorisation de l'album + partageService.share(photo.getId(), p.getUtilisateur().getEmail(), p.getPermission().name(), requesterEmail); + } + }); + // S'assurer que le propriétaire a aussi accès + boolean ownerHasAccess = photo.getPartages().stream() + .anyMatch(p -> p.getUtilisateur().getEmail().equals(album.getProprietaire().getEmail())); + + if (!ownerHasAccess) { + partageService.share(photo.getId(), album.getProprietaire().getEmail(), "ADMIN", requesterEmail); + } + + } + + + + @Override + public void removePhoto(Long albumId, Long photoId, String ownerEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + if (!album.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n'êtes pas propriétaire de l’album"); + Photo photo = photoRepository.findById(photoId) + .orElseThrow(() -> new RuntimeException("Photo introuvable")); + album.getPhotos().remove(photo); + albumRepository.save(album); + } + + @Override + public void deleteAlbum(Long albumId, String ownerEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + if (!album.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n'êtes pas propriétaire de l’album"); + albumRepository.delete(album); + } + + @Override + public void shareAlbum(Long albumId, String targetEmail, String permission, String ownerEmail) { + partageService.shareAlbum(albumId, targetEmail, permission, ownerEmail); + } + + @Override + public void updateAlbumPermission(Long albumId, String targetEmail, String permission, String ownerEmail) { + partageService.updateAlbumPermission(albumId, targetEmail, permission, ownerEmail); + // --- Synchroniser les permissions sur toutes les photos de l’album --- + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + for (Photo photo : album.getPhotos()) { + // Chercher un partage photo existant + Partage partagePhoto = photo.getPartages().stream() + .filter(p -> p.getUtilisateur().getEmail().equals(targetEmail)) + .findFirst() + .orElse(null); + if (partagePhoto != null) { + // Mettre à jour la permission + partagePhoto.setPermission(Partage.Permission.valueOf(permission)); + partageRepository.save(partagePhoto); + } else { + // Si pas encore partagé → création + partageService.share( + photo.getId(), + targetEmail, + permission, + ownerEmail + ); + } + } + } + + + @Override + public void removeAlbumShare(Long albumId, String targetEmail, String ownerEmail) { + partageService.removeAlbumShare(albumId, targetEmail, ownerEmail); + } + + + + @Override + public List getAlbumPartages(Long albumId) { + return partageService.getAlbumPartages(albumId); + } + + @Override + public List listAlbumsSharedWithMe(String email) { + return albumRepository.findByPartages_Utilisateur_Email(email) + .stream() + .filter(a -> !a.getProprietaire().getEmail().equals(email)) + .map(AlbumMapper::toDTO) + .toList(); + } + + + + + + +} diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java index 6c432fb..f0b9b48 100644 --- a/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java +++ b/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java @@ -2,9 +2,11 @@ package local.epul4a.fotosharing.service.impl; import local.epul4a.fotosharing.dto.PartageDTO; import local.epul4a.fotosharing.mapper.PartageMapper; +import local.epul4a.fotosharing.model.Album; import local.epul4a.fotosharing.model.Partage; import local.epul4a.fotosharing.model.Photo; import local.epul4a.fotosharing.model.Utilisateur; +import local.epul4a.fotosharing.repository.AlbumRepository; import local.epul4a.fotosharing.repository.PartageRepository; import local.epul4a.fotosharing.repository.PhotoRepository; import local.epul4a.fotosharing.repository.UtilisateurRepository; @@ -19,15 +21,18 @@ public class PartageServiceImpl implements PartageService { private final PartageRepository partageRepository; private final PhotoRepository photoRepository; private final UtilisateurRepository utilisateurRepository; + private final AlbumRepository albumRepository; public PartageServiceImpl( PartageRepository partageRepository, PhotoRepository photoRepository, - UtilisateurRepository utilisateurRepository + UtilisateurRepository utilisateurRepository, + AlbumRepository albumRepository ) { this.partageRepository = partageRepository; this.photoRepository = photoRepository; this.utilisateurRepository = utilisateurRepository; + this.albumRepository = albumRepository; } @Override @@ -62,11 +67,7 @@ public class PartageServiceImpl implements PartageService { @Override public void unshare(Long photoId, String targetEmail) { - Partage partage = partageRepository.findByPhoto_Id(photoId) - .stream() - .filter(p -> p.getUtilisateur().getEmail().equals(targetEmail)) - .findFirst() - .orElse(null); + Partage partage = partageRepository.findByPhoto_Id(photoId).stream().filter(p -> p.getUtilisateur().getEmail().equals(targetEmail)).findFirst().orElse(null); if (partage != null) partageRepository.delete(partage); @@ -82,9 +83,7 @@ public class PartageServiceImpl implements PartageService { // Photo publique => tout le monde peut voir if (photo.getVisibilite() == Photo.Visibilite.PUBLIC) return true; - Partage partage = partageRepository - .findByPhoto_IdAndUtilisateur_Email(photoId, email) - .orElse(null); + Partage partage = partageRepository.findByPhoto_IdAndUtilisateur_Email(photoId, email); return partage != null; // READ / COMMENT / ADMIN } @@ -95,9 +94,7 @@ public class PartageServiceImpl implements PartageService { // propriétaire = admin total if (photo.getProprietaire().getEmail().equals(email)) return true; - Partage partage = partageRepository - .findByPhoto_IdAndUtilisateur_Email(photoId, email) - .orElse(null); + Partage partage = partageRepository.findByPhoto_IdAndUtilisateur_Email(photoId, email); if (partage == null) return false; return partage.getPermission() == Partage.Permission.COMMENT || partage.getPermission() == Partage.Permission.ADMIN; @@ -110,9 +107,7 @@ public class PartageServiceImpl implements PartageService { // propriétaire = admin total if (photo.getProprietaire().getEmail().equals(email)) return true; - Partage partage = partageRepository - .findByPhoto_IdAndUtilisateur_Email(photoId, email) - .orElse(null); + Partage partage = partageRepository.findByPhoto_IdAndUtilisateur_Email(photoId, email); if (partage == null) return false; return partage.getPermission() == Partage.Permission.ADMIN; } @@ -121,28 +116,154 @@ public class PartageServiceImpl implements PartageService { public void updatePermission(Long photoId, String targetEmail, String newPermission, String requesterEmail) { Photo photo = photoRepository.findById(photoId) .orElseThrow(() -> new RuntimeException("Photo introuvable")); - //Vérifier si requester = propriétaire + // Si ce n'est pas le propriétaire → vérifier si ADMIN if (!photo.getProprietaire().getEmail().equals(requesterEmail)) { - // Sinon, vérifier s'il a ADMIN - Partage requesterPartage = partageRepository - .findByPhoto_IdAndUtilisateur_Email(photoId, requesterEmail) - .orElse(null); - if (requesterPartage == null || requesterPartage.getPermission() != Partage.Permission.ADMIN) { + Partage requesterPartage = + partageRepository.findByPhoto_IdAndUtilisateur_Email(photoId, requesterEmail); + if (requesterPartage == null || + requesterPartage.getPermission() != Partage.Permission.ADMIN) { throw new RuntimeException("Vous n’avez pas les droits ADMIN pour modifier les permissions."); } } - // OK → modification des droits - Partage partage = partageRepository - .findByPhoto_IdAndUtilisateur_Email(photoId, targetEmail) - .orElseThrow(() -> new RuntimeException("Partage introuvable")); - Partage.Permission permission = Partage.Permission.valueOf(newPermission); - partage.setPermission(permission); + Partage partage = + partageRepository.findByPhoto_IdAndUtilisateur_Email(photoId, targetEmail); + if (partage == null) + throw new RuntimeException("Partage introuvable"); + partage.setPermission(Partage.Permission.valueOf(newPermission)); partageRepository.save(partage); } + @Override public int countShares(Long photoId) { return partageRepository.countByPhoto_Id(photoId); } + @Override + public void shareAlbum(Long albumId, String targetEmail, String permissionStr, String ownerEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + if (!album.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n’êtes pas propriétaire de cet album"); + Utilisateur target = utilisateurRepository.findByEmail(targetEmail) + .orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); + if (partageRepository.existsByAlbum_IdAndUtilisateur_Email(albumId, targetEmail)) + throw new RuntimeException("Cet utilisateur a déjà accès à cet album"); + //Créer le partage ALBUM + Partage.Permission permission = Partage.Permission.valueOf(permissionStr); + Partage partage = new Partage(); + partage.setAlbum(album); + partage.setUtilisateur(target); + partage.setPermission(permission); + partageRepository.save(partage); + //Créer le partage PHOTO pour toutes les photos existantes + for (Photo photo : album.getPhotos()) { + boolean exists = partageRepository.existsByPhoto_IdAndUtilisateur_Email(photo.getId(), targetEmail); + if (!exists) { + Partage p = new Partage(); + p.setPhoto(photo); + p.setUtilisateur(target); + p.setPermission(permission); + partageRepository.save(p); + } + } + } + + + @Override + public void updateAlbumPermission(Long albumId, String targetEmail, String newPermission, String ownerEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + if (!album.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n’êtes pas propriétaire"); + Partage partageAlbum = partageRepository.findByAlbum_IdAndUtilisateur_Email(albumId, targetEmail); + if (partageAlbum == null) + throw new RuntimeException("Partage introuvable"); + Partage.Permission perm = Partage.Permission.valueOf(newPermission); + //Mettre à jour permission sur ALBUM + partageAlbum.setPermission(perm); + partageRepository.save(partageAlbum); + //Mettre à jour permissions sur toutes les PHOTOS + for (Photo photo : album.getPhotos()) { + Partage partagePhoto = partageRepository.findByPhoto_IdAndUtilisateur_Email(photo.getId(), targetEmail); + if (partagePhoto != null) { + partagePhoto.setPermission(perm); + partageRepository.save(partagePhoto); + } + } + } + + + + @Override + public boolean canViewAlbum(Long albumId, String email) { + Album album = albumRepository.findById(albumId).orElse(null); + if (album == null) return false; + if (album.getVisibilite() == Album.Visibilite.PUBLIC) + return true; + if (album.getProprietaire().getEmail().equals(email)) + return true; + return partageRepository.existsByAlbum_IdAndUtilisateur_Email(albumId, email); + } + + @Override + public List getAlbumPartages(Long albumId) { + return partageRepository.findByAlbum_Id(albumId) + .stream() + .map(PartageMapper::toDTO) + .toList(); + } + + @Override + public boolean canCommentAlbum(Long albumId, String email) { + Album album = albumRepository.findById(albumId).orElse(null); + if (album == null) return false; + //Le propriétaire : autorisé à tout + if (album.getProprietaire().getEmail().equals(email)) + return true; + //Chercher un partage + Partage partage = partageRepository.findByAlbum_IdAndUtilisateur_Email(albumId, email); + if (partage == null) return false; + //COMMENT autorisé pour COMMENT et ADMIN + return partage.getPermission() == Partage.Permission.COMMENT + || partage.getPermission() == Partage.Permission.ADMIN; + } + + + @Override + public boolean canAdminAlbum(Long albumId, String email) { + Album album = albumRepository.findById(albumId).orElse(null); + if (album == null) return false; + //Le propriétaire est toujours ADMIN + if (album.getProprietaire().getEmail().equals(email)) + return true; + //hercher un partage + Partage partage = partageRepository.findByAlbum_IdAndUtilisateur_Email(albumId, email); + if (partage == null) return false; + //ADMIN uniquement si permission ADMIN + return partage.getPermission() == Partage.Permission.ADMIN; + } + + @Override + public void removeAlbumShare(Long albumId, String targetEmail, String ownerEmail) { + Album album = albumRepository.findById(albumId) + .orElseThrow(() -> new RuntimeException("Album introuvable")); + // Vérification propriétaire + if (!album.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n’êtes pas propriétaire"); + //Supprimer le partage ALBUM + Partage partageAlbum = partageRepository.findByAlbum_IdAndUtilisateur_Email(albumId, targetEmail); + if (partageAlbum != null) { + partageRepository.delete(partageAlbum); + } + //Supprimer les partages sur toutes les photos + for (Photo photo : album.getPhotos()) { + Partage partagePhoto = partageRepository.findByPhoto_IdAndUtilisateur_Email(photo.getId(), targetEmail); + if (partagePhoto != null) { + partageRepository.delete(partagePhoto); + } + } + } + + } diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java index 413dfed..fac5d6e 100644 --- a/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java +++ b/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java @@ -134,12 +134,13 @@ public class PhotoServiceImpl implements PhotoService { //============= PHOTOS SHARED WITH USER ================== @Override public Page listSharedWith(String email, int page, int size) { - List photos = - partageRepository.findByUtilisateur_Email(email) - .stream() - .map(Partage::getPhoto) - .map(PhotoMapper::toDTO) - .toList(); + List photos = partageRepository.findByUtilisateur_Email(email) + .stream() + .map(Partage::getPhoto) + .filter(photo -> photo != null) + .map(PhotoMapper::toDTO) + .filter(dto -> dto != null) + .toList(); int start = page * size; int end = Math.min(start + size, photos.size()); List sub = photos.subList(start, end); @@ -147,6 +148,7 @@ public class PhotoServiceImpl implements PhotoService { } + //============= PHOTOS SET AS SHARED BY USER ============= @Override public Page listSharedPhotos(String email, int page, int size) { @@ -155,4 +157,15 @@ public class PhotoServiceImpl implements PhotoService { .findByProprietaire_EmailAndVisibilite(email, Photo.Visibilite.SHARED, pageable) .map(PhotoMapper::toDTO); } + + //============= ALL PHOTOS OF USER ======================= + @Override + public List listAllPhotosOfUser(String email) { + + return photoRepository.findByProprietaire_Email(email) + .stream() + .map(PhotoMapper::toDTO) + .toList(); + } + } \ No newline at end of file diff --git a/src/main/resources/templates/album-detail.html b/src/main/resources/templates/album-detail.html new file mode 100644 index 0000000..5bad9a3 --- /dev/null +++ b/src/main/resources/templates/album-detail.html @@ -0,0 +1,101 @@ + + + + + Détail album + + + +⬅ Retour aux albums +

+

Description :

+

Propriétaire :

+

Visibilité :

+
+ +

Photos dans l’album

+
+ + + +
+ Retirer +
+ + + + + +
+ +
+ +

Ajouter une photo

+
+ Photo ajoutée ! +
+
+ + + +
+
+

Gestion des partages de l’album

+
+ +
+ +
+ + + + + +
+

Utilisateurs ayant accès :

+ + + + + + + + + + + + +
UtilisateurPermissionActions
+
+ + + +
+
+ Retirer +
+
+ + + Supprimer l’album + +
+ + + + + diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index a5135cc..3442f17 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -7,6 +7,7 @@

Bienvenue sur FotoSharing

Uploader une photo

Voir mes photos

+

Voir mes albums

Voir la galerie publique

diff --git a/src/main/resources/templates/mes-albums.html b/src/main/resources/templates/mes-albums.html new file mode 100644 index 0000000..4f692aa --- /dev/null +++ b/src/main/resources/templates/mes-albums.html @@ -0,0 +1,70 @@ + + + + + Mes albums + + + +

Mes albums

+ + +

Créer un album

+ + + +
+ +
+ + + +
+
+ + +

Liste de mes albums

+
+ + + + +

+
+ + +
+ + + +
+ +
+ +

Albums partagés avec moi

+
+

Aucun album ne vous a été partagé.

+
+
+
+
+ + + +

+ Partagé par : + +

+
+
+
+ + + + diff --git a/src/main/resources/templates/mes-photos.html b/src/main/resources/templates/mes-photos.html index 569bc48..765dd54 100644 --- a/src/main/resources/templates/mes-photos.html +++ b/src/main/resources/templates/mes-photos.html @@ -10,7 +10,7 @@

Retour accueil

Mes photos privées

- @@ -26,7 +26,7 @@

Mes photos publiques

- @@ -42,8 +42,8 @@

Mes photos partagées

-
- +
+ @@ -76,6 +76,7 @@

Photos partagées avec moi

diff --git a/target/classes/local/epul4a/fotosharing/controller/AlbumController.class b/target/classes/local/epul4a/fotosharing/controller/AlbumController.class new file mode 100644 index 0000000..7b09bf6 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/controller/AlbumController.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/AlbumDTO.class b/target/classes/local/epul4a/fotosharing/dto/AlbumDTO.class new file mode 100644 index 0000000..fb4dc4c Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/dto/AlbumDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class b/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class index 3537079..afa4fe0 100644 Binary files a/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class and b/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/mapper/AlbumMapper.class b/target/classes/local/epul4a/fotosharing/mapper/AlbumMapper.class new file mode 100644 index 0000000..e4f4e69 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/mapper/AlbumMapper.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Album$Visibilite.class b/target/classes/local/epul4a/fotosharing/model/Album$Visibilite.class new file mode 100644 index 0000000..0c108a1 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/model/Album$Visibilite.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Album.class b/target/classes/local/epul4a/fotosharing/model/Album.class new file mode 100644 index 0000000..18c6b63 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/model/Album.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class b/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class index 79e7c8d..db2e6ea 100644 Binary files a/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class and b/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Partage.class b/target/classes/local/epul4a/fotosharing/model/Partage.class index 3315188..1cc6295 100644 Binary files a/target/classes/local/epul4a/fotosharing/model/Partage.class and b/target/classes/local/epul4a/fotosharing/model/Partage.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Photo$Visibilite.class b/target/classes/local/epul4a/fotosharing/model/Photo$Visibilite.class index 5f8d68f..b4c973c 100644 Binary files a/target/classes/local/epul4a/fotosharing/model/Photo$Visibilite.class and b/target/classes/local/epul4a/fotosharing/model/Photo$Visibilite.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Photo.class b/target/classes/local/epul4a/fotosharing/model/Photo.class index dda4a88..5d75641 100644 Binary files a/target/classes/local/epul4a/fotosharing/model/Photo.class and b/target/classes/local/epul4a/fotosharing/model/Photo.class differ diff --git a/target/classes/local/epul4a/fotosharing/repository/AlbumRepository.class b/target/classes/local/epul4a/fotosharing/repository/AlbumRepository.class new file mode 100644 index 0000000..65daaa5 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/repository/AlbumRepository.class differ diff --git a/target/classes/local/epul4a/fotosharing/repository/PartageRepository.class b/target/classes/local/epul4a/fotosharing/repository/PartageRepository.class index e565f87..85dfab8 100644 Binary files a/target/classes/local/epul4a/fotosharing/repository/PartageRepository.class and b/target/classes/local/epul4a/fotosharing/repository/PartageRepository.class differ diff --git a/target/classes/local/epul4a/fotosharing/security/CustomUserDetailsService.class b/target/classes/local/epul4a/fotosharing/security/CustomUserDetailsService.class index ad9e87a..6cbfc95 100644 Binary files a/target/classes/local/epul4a/fotosharing/security/CustomUserDetailsService.class and b/target/classes/local/epul4a/fotosharing/security/CustomUserDetailsService.class differ diff --git a/target/classes/local/epul4a/fotosharing/security/SecurityConfig.class b/target/classes/local/epul4a/fotosharing/security/SecurityConfig.class index c4a7638..7813d21 100644 Binary files a/target/classes/local/epul4a/fotosharing/security/SecurityConfig.class and b/target/classes/local/epul4a/fotosharing/security/SecurityConfig.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/AlbumService.class b/target/classes/local/epul4a/fotosharing/service/AlbumService.class new file mode 100644 index 0000000..d99efff Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/service/AlbumService.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/PartageService.class b/target/classes/local/epul4a/fotosharing/service/PartageService.class index 72df5ff..9d23ae9 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/PartageService.class and b/target/classes/local/epul4a/fotosharing/service/PartageService.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/PhotoService.class b/target/classes/local/epul4a/fotosharing/service/PhotoService.class index c370058..a2c5e77 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/PhotoService.class and b/target/classes/local/epul4a/fotosharing/service/PhotoService.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.class new file mode 100644 index 0000000..05dc762 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/service/impl/AlbumServiceImpl.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class index 4816c7c..18414b6 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class and b/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.class index 0cd1326..934d9ef 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.class and b/target/classes/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.class differ diff --git a/target/classes/templates/album-detail.html b/target/classes/templates/album-detail.html new file mode 100644 index 0000000..5bad9a3 --- /dev/null +++ b/target/classes/templates/album-detail.html @@ -0,0 +1,101 @@ + + + + + Détail album + + + +⬅ Retour aux albums +

+

Description :

+

Propriétaire :

+

Visibilité :

+
+ +

Photos dans l’album

+
+ + + +
+ Retirer +
+ + + + + +
+ +
+ +

Ajouter une photo

+
+ Photo ajoutée ! +
+
+ + + +
+
+

Gestion des partages de l’album

+
+ +
+ +
+ + + + + +
+

Utilisateurs ayant accès :

+ + + + + + + + + + + + +
UtilisateurPermissionActions
+
+ + + +
+
+ Retirer +
+
+ + + Supprimer l’album + +
+ + + + + diff --git a/target/classes/templates/home.html b/target/classes/templates/home.html index a5135cc..3442f17 100644 --- a/target/classes/templates/home.html +++ b/target/classes/templates/home.html @@ -7,6 +7,7 @@

Bienvenue sur FotoSharing

Uploader une photo

Voir mes photos

+

Voir mes albums

Voir la galerie publique

diff --git a/target/classes/templates/mes-albums.html b/target/classes/templates/mes-albums.html new file mode 100644 index 0000000..4f692aa --- /dev/null +++ b/target/classes/templates/mes-albums.html @@ -0,0 +1,70 @@ + + + + + Mes albums + + + +

Mes albums

+ + +

Créer un album

+ + + +
+ +
+ + + +
+
+ + +

Liste de mes albums

+
+ + + + +

+
+ + +
+ + + +
+ +
+ +

Albums partagés avec moi

+
+

Aucun album ne vous a été partagé.

+
+
+
+
+ + + +

+ Partagé par : + +

+
+
+
+ + + + diff --git a/target/classes/templates/mes-photos.html b/target/classes/templates/mes-photos.html index 569bc48..765dd54 100644 --- a/target/classes/templates/mes-photos.html +++ b/target/classes/templates/mes-photos.html @@ -10,7 +10,7 @@

Retour accueil

Mes photos privées

- @@ -26,7 +26,7 @@

Mes photos publiques

- @@ -42,8 +42,8 @@

Mes photos partagées

-
- +
+ @@ -76,6 +76,7 @@

Photos partagées avec moi