diff --git a/src/main/java/local/epul4a/fotosharing/controller/PhotoController.java b/src/main/java/local/epul4a/fotosharing/controller/PhotoController.java index 7df688e..3049b02 100644 --- a/src/main/java/local/epul4a/fotosharing/controller/PhotoController.java +++ b/src/main/java/local/epul4a/fotosharing/controller/PhotoController.java @@ -1,49 +1,46 @@ package local.epul4a.fotosharing.controller; -import local.epul4a.fotosharing.model.Partage; -import local.epul4a.fotosharing.model.Photo; -import local.epul4a.fotosharing.model.Utilisateur; -import local.epul4a.fotosharing.repository.PartageRepository; -import local.epul4a.fotosharing.repository.PhotoRepository; -import local.epul4a.fotosharing.repository.UtilisateurRepository; -import local.epul4a.fotosharing.security.CustomUserDetails; +import local.epul4a.fotosharing.dto.CommentaireDTO; +import local.epul4a.fotosharing.dto.PartageDTO; +import local.epul4a.fotosharing.dto.PhotoDTO; import local.epul4a.fotosharing.service.CommentaireService; +import local.epul4a.fotosharing.service.PartageService; import local.epul4a.fotosharing.service.PhotoService; +import local.epul4a.fotosharing.service.UtilisateurService; import org.springframework.core.io.Resource; -import org.springframework.core.io.PathResource; import org.springframework.data.domain.Page; -import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - @Controller public class PhotoController { private final PhotoService photoService; - private final PhotoRepository photoRepository; private final CommentaireService commentaireService; - private final UtilisateurRepository utilisateurRepository; - private final PartageRepository partageRepository; + private final PartageService partageService; + private final UtilisateurService utilisateurService; - public PhotoController(PhotoService photoService, PhotoRepository photoRepository, CommentaireService commentaireService, UtilisateurRepository utilisateurRepository, PartageRepository partageRepository) { + public PhotoController( + PhotoService photoService, + CommentaireService commentaireService, + PartageService partageService, + UtilisateurService utilisateurService + ) { this.photoService = photoService; - this.photoRepository = photoRepository; this.commentaireService = commentaireService; - this.utilisateurRepository = utilisateurRepository; - this.partageRepository = partageRepository; + this.partageService = partageService; + this.utilisateurService = utilisateurService; } + + /* ========================== UPLOAD ========================== */ + @GetMapping("/upload") public String uploadForm() { return "upload"; @@ -52,147 +49,142 @@ public class PhotoController { @PostMapping("/upload") public String doUpload(@RequestParam("file") MultipartFile file, @RequestParam(value = "visibilite", defaultValue = "PRIVATE") String visibilite, - Authentication authentication, + Authentication auth, Model model) { try { - String email = authentication.getName(); // l'email de l'utilisateur connecté - Photo p = photoService.store(file, visibilite, email); - model.addAttribute("message", "Upload OK : " + p.getId()); - return "redirect:/"; - } catch (Exception e) { - model.addAttribute("error", e.getMessage()); + photoService.store(file, visibilite, auth.getName()); + return "redirect:/mes-photos"; + } catch (Exception ex) { + model.addAttribute("error", ex.getMessage()); return "upload"; } } + + /* ========================== RAW IMAGE ========================== */ + @GetMapping("/photo/{id}/raw") - public ResponseEntity rawPhoto(@PathVariable("id") Long id) { - Photo photo = photoRepository.findById(id).orElse(null); - if (photo == null) { + public ResponseEntity rawPhoto(@PathVariable Long id) { + + PhotoDTO photo = photoService.getPhotoById(id); + if (photo == null) return ResponseEntity.notFound().build(); - } - Path p = photoService.loadAsPath(photo.getUuidFichier()); - Resource r = new PathResource(p); - - if (!r.exists()) { + Resource r = photoService.loadAsResource(photo.getUuidFichier()); + if (!r.exists()) return ResponseEntity.notFound().build(); - } - - String contentType = "application/octet-stream"; - try { - contentType = Files.probeContentType(p); - } catch (Exception ignored) { - } return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(contentType)) - .header(HttpHeaders.CONTENT_DISPOSITION, - "inline; filename=\"" + photo.getNomFichierOriginal() + "\"") + .contentType(MediaType.IMAGE_JPEG) // simplifiable, ou détecté dans service .body(r); } + + /* ========================== MES PHOTOS ========================== */ + @GetMapping("/mes-photos") public String mesPhotos( - @RequestParam(name = "pagePrivees", defaultValue = "0") int pagePrivees, - @RequestParam(name = "pagePubliques", defaultValue = "0") int pagePubliques, - @RequestParam(name = "pagePartagees", defaultValue = "0") int pagePartagees, - @RequestParam(name = "pageMesPartagees", defaultValue = "0") int pageMesPartagees, - Model model, - Authentication auth - ) { - String email = auth.getName(); - // Chaque liste utilise sa propre pagination - model.addAttribute("photosPrivees", photoService.listPrivatePhotos(email, pagePrivees, 12)); - model.addAttribute("photosPubliques", photoService.listPublicPhotos(email, pagePubliques, 12)); - model.addAttribute("photosPartagees", photoService.listSharedWith(email, pagePartagees, 12)); - model.addAttribute("mesPhotosPartagees", photoService.listSharedPhotos(email, pageMesPartagees, 12)); + @RequestParam(defaultValue = "0") int pagePrivees, + @RequestParam(defaultValue = "0") int pagePubliques, + @RequestParam(defaultValue = "0") int pagePartagees, + @RequestParam(defaultValue = "0") int pageMesPartagees, + Authentication auth, Model model) { + + String email = auth.getName(); + + model.addAttribute("photosPrivees", + photoService.listPrivatePhotos(email, pagePrivees, 12)); + + model.addAttribute("photosPubliques", + photoService.listPublicPhotos(email, pagePubliques, 12)); + + model.addAttribute("photosPartagees", + photoService.listSharedWith(email, pagePartagees, 12)); + + model.addAttribute("mesPhotosPartagees", + photoService.listSharedPhotos(email, pageMesPartagees, 12)); - // Ajouter les 3 index séparés model.addAttribute("pagePrivees", pagePrivees); model.addAttribute("pagePubliques", pagePubliques); model.addAttribute("pagePartagees", pagePartagees); model.addAttribute("pageMesPartagees", pageMesPartagees); + return "mes-photos"; } + /* ========================== GALERIE ========================== */ + @GetMapping("/galerie") public String galerie(@RequestParam(defaultValue = "0") int page, Model model) { - Page photosPage = photoService.listPublic(page, 12); + + Page photosPage = photoService.listPublic(page, 12); + model.addAttribute("photosPage", photosPage); model.addAttribute("currentPage", page); + return "galerie"; } + /* ========================== DETAIL PHOTO ========================== */ + @GetMapping("/photo/{id}") @PreAuthorize("@securityService.canAccessPhoto(authentication, #id)") public String viewPhoto(@PathVariable Long id, @RequestParam(defaultValue = "0") int page, - Model model, - Authentication auth) { - Photo photo = photoRepository.findById(id).orElse(null); - if (photo == null) { + Authentication auth, + Model model) { + + PhotoDTO photo = photoService.getPhotoById(id); + if (photo == null) return "redirect:/galerie"; - } + model.addAttribute("photo", photo); - // Pagination des commentaires - model.addAttribute("commentairesPage", - commentaireService.listByPhoto(id, page, 10)); + + Page commentaires = + commentaireService.listByPhoto(id, page, 10); + model.addAttribute("commentairesPage", commentaires); model.addAttribute("currentPage", page); - // utilisateur connecté (peut être null) + String currentUser = (auth != null ? auth.getName() : null); model.addAttribute("currentUser", currentUser); - // Liste des partages - List partages = partageRepository.findByPhoto_Id(id); - model.addAttribute("partages", partages); + + model.addAttribute("partages", + partageService.getPartagesForPhoto(id)); + return "photo-detail"; } + /* ========================== COMMENTAIRES ========================== */ @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); + + commentaireService.addComment(id, auth.getName(), contenu); return "redirect:/photo/" + id; } + + /* ========================== PARTAGE PHOTO ========================== */ @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); + public String sharePhoto(@PathVariable Long id, + @RequestParam String email, + @RequestParam String permission, + Authentication auth) { + + partageService.share(id, email, permission, auth.getName()); return "redirect:/photo/" + id + "?shared=ok"; } + @GetMapping("/photo/{id}/unshare/{email}") public String unshare(@PathVariable Long id, @PathVariable String email) { - photoService.unshare(id, email); + + partageService.unshare(id, email); return "redirect:/photo/" + id; } - - -} - +} \ No newline at end of file diff --git a/src/main/java/local/epul4a/fotosharing/dto/CommentaireDTO.java b/src/main/java/local/epul4a/fotosharing/dto/CommentaireDTO.java new file mode 100644 index 0000000..cdb9bf7 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/dto/CommentaireDTO.java @@ -0,0 +1,15 @@ +package local.epul4a.fotosharing.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +public class CommentaireDTO { + private Long id; + private String contenu; + private LocalDateTime dateCommentaire; + private UtilisateurDTO auteur; +} diff --git a/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java b/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java new file mode 100644 index 0000000..c4defd2 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/dto/PartageDTO.java @@ -0,0 +1,13 @@ +package local.epul4a.fotosharing.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PartageDTO { + private Long id; + private UtilisateurDTO utilisateur; + private String permission; // READ / COMMENT / ADMIN + private PhotoDTO photo; +} diff --git a/src/main/java/local/epul4a/fotosharing/dto/PhotoDTO.java b/src/main/java/local/epul4a/fotosharing/dto/PhotoDTO.java new file mode 100644 index 0000000..fcb5d90 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/dto/PhotoDTO.java @@ -0,0 +1,19 @@ +package local.epul4a.fotosharing.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +public class PhotoDTO { + + private Long id; + private String nomFichierOriginal; + private String uuidFichier; + private LocalDateTime dateUpload; + private String visibilite; + private UtilisateurDTO proprietaire; + +} diff --git a/src/main/java/local/epul4a/fotosharing/dto/UtilisateurDTO.java b/src/main/java/local/epul4a/fotosharing/dto/UtilisateurDTO.java new file mode 100644 index 0000000..11951b9 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/dto/UtilisateurDTO.java @@ -0,0 +1,14 @@ +package local.epul4a.fotosharing.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class UtilisateurDTO { + + private Long id; + private String email; + private String nom; + private String prenom; +} diff --git a/src/main/java/local/epul4a/fotosharing/mapper/CommentaireMapper.java b/src/main/java/local/epul4a/fotosharing/mapper/CommentaireMapper.java new file mode 100644 index 0000000..7c91724 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/mapper/CommentaireMapper.java @@ -0,0 +1,18 @@ +package local.epul4a.fotosharing.mapper; + +import local.epul4a.fotosharing.dto.CommentaireDTO; +import local.epul4a.fotosharing.model.Commentaire; + +public class CommentaireMapper { + + public static CommentaireDTO toDTO(Commentaire c) { + if (c == null) return null; + CommentaireDTO dto = new CommentaireDTO(); + dto.setId(c.getId()); + dto.setContenu(c.getContenu()); + dto.setDateCommentaire(c.getDateCommentaire()); + // Auteur via mapper dédié + dto.setAuteur(UtilisateurMapper.toDTO(c.getAuteur())); + return dto; + } +} diff --git a/src/main/java/local/epul4a/fotosharing/mapper/PartageMapper.java b/src/main/java/local/epul4a/fotosharing/mapper/PartageMapper.java new file mode 100644 index 0000000..d7b59c8 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/mapper/PartageMapper.java @@ -0,0 +1,20 @@ +package local.epul4a.fotosharing.mapper; + +import local.epul4a.fotosharing.dto.PartageDTO; +import local.epul4a.fotosharing.model.Partage; + +public class PartageMapper { + + public static PartageDTO toDTO(Partage p) { + if (p == null) return null; + + PartageDTO dto = new PartageDTO(); + dto.setId(p.getId()); + dto.setUtilisateur(UtilisateurMapper.toDTO(p.getUtilisateur())); + dto.setPhoto(PhotoMapper.toDTO(p.getPhoto())); + dto.setPermission(p.getPermission().name()); + + return dto; + } +} + diff --git a/src/main/java/local/epul4a/fotosharing/mapper/PhotoMapper.java b/src/main/java/local/epul4a/fotosharing/mapper/PhotoMapper.java new file mode 100644 index 0000000..a38cb75 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/mapper/PhotoMapper.java @@ -0,0 +1,28 @@ +package local.epul4a.fotosharing.mapper; + +import local.epul4a.fotosharing.dto.PhotoDTO; +import local.epul4a.fotosharing.dto.UtilisateurDTO; +import local.epul4a.fotosharing.model.Photo; +import local.epul4a.fotosharing.model.Utilisateur; + +public class PhotoMapper { + public static PhotoDTO toDTO(Photo p) { + if (p == null) return null; + PhotoDTO dto = new PhotoDTO(); + dto.setId(p.getId()); + dto.setNomFichierOriginal(p.getNomFichierOriginal()); + dto.setUuidFichier(p.getUuidFichier()); + dto.setDateUpload(p.getDateUpload()); + dto.setVisibilite(p.getVisibilite().name()); + Utilisateur u = p.getProprietaire(); + if (u != null) { + UtilisateurDTO uDTO = new UtilisateurDTO(); + uDTO.setId(u.getId()); + uDTO.setEmail(u.getEmail()); + uDTO.setNom(u.getNom()); + uDTO.setPrenom(u.getPrenom()); + dto.setProprietaire(uDTO); + } + return dto; + } +} diff --git a/src/main/java/local/epul4a/fotosharing/mapper/UtilisateurMapper.java b/src/main/java/local/epul4a/fotosharing/mapper/UtilisateurMapper.java new file mode 100644 index 0000000..77f830e --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/mapper/UtilisateurMapper.java @@ -0,0 +1,17 @@ +package local.epul4a.fotosharing.mapper; + +import local.epul4a.fotosharing.dto.UtilisateurDTO; +import local.epul4a.fotosharing.model.Utilisateur; + +public class UtilisateurMapper { + + public static UtilisateurDTO toDTO(Utilisateur u) { + if (u == null) return null; + UtilisateurDTO dto = new UtilisateurDTO(); + dto.setId(u.getId()); + dto.setEmail(u.getEmail()); + dto.setNom(u.getNom()); + dto.setPrenom(u.getPrenom()); + return dto; + } +} diff --git a/src/main/java/local/epul4a/fotosharing/model/Partage.java b/src/main/java/local/epul4a/fotosharing/model/Partage.java index 9f6aef2..0e564eb 100644 --- a/src/main/java/local/epul4a/fotosharing/model/Partage.java +++ b/src/main/java/local/epul4a/fotosharing/model/Partage.java @@ -8,6 +8,11 @@ import lombok.Setter; @Getter @Setter public class Partage { + public enum Permission { + READ, + COMMENT, + ADMIN + } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -21,5 +26,7 @@ public class Partage { @JoinColumn(name = "id_utilisateur") private Utilisateur utilisateur; - // Getters & Setters + @Enumerated(EnumType.STRING) + private Permission permission = Permission.READ; + } diff --git a/src/main/java/local/epul4a/fotosharing/service/CommentaireService.java b/src/main/java/local/epul4a/fotosharing/service/CommentaireService.java index 84d4dff..e1ba02e 100644 --- a/src/main/java/local/epul4a/fotosharing/service/CommentaireService.java +++ b/src/main/java/local/epul4a/fotosharing/service/CommentaireService.java @@ -1,5 +1,6 @@ package local.epul4a.fotosharing.service; +import local.epul4a.fotosharing.dto.CommentaireDTO; import local.epul4a.fotosharing.model.Commentaire; import org.springframework.data.domain.Page; @@ -8,6 +9,6 @@ import java.util.List; public interface CommentaireService { List listByPhoto(Long photoId); void addComment(Long photoId, String email, String contenu); - Page listByPhoto(Long photoId, int page, int size); + Page listByPhoto(Long photoId, int page, int size); } diff --git a/src/main/java/local/epul4a/fotosharing/service/PartageService.java b/src/main/java/local/epul4a/fotosharing/service/PartageService.java new file mode 100644 index 0000000..3f7e6a2 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/PartageService.java @@ -0,0 +1,10 @@ +package local.epul4a.fotosharing.service; + +import local.epul4a.fotosharing.dto.PartageDTO; +import java.util.List; + +public interface PartageService { + void share(Long photoId, String targetEmail, String permission, String ownerEmail); + void unshare(Long photoId, String targetEmail); + List getPartagesForPhoto(Long photoId); +} diff --git a/src/main/java/local/epul4a/fotosharing/service/PhotoService.java b/src/main/java/local/epul4a/fotosharing/service/PhotoService.java index 0142705..5a9b8cf 100644 --- a/src/main/java/local/epul4a/fotosharing/service/PhotoService.java +++ b/src/main/java/local/epul4a/fotosharing/service/PhotoService.java @@ -1,6 +1,8 @@ package local.epul4a.fotosharing.service; +import local.epul4a.fotosharing.dto.PhotoDTO; import local.epul4a.fotosharing.model.Photo; +import org.springframework.core.io.Resource; import org.springframework.data.domain.Page; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -8,19 +10,14 @@ import java.nio.file.Path; import java.util.List; public interface PhotoService { - Photo store(MultipartFile file, String visibilite, String ownerEmail) throws IOException; - Path loadAsPath(String uuidFile); - List listByOwner(String email); - List listPublicPhotos(); - List listSharedWith(String email); - List listPrivatePhotos(String email); - List listPublicPhotos(String email); - void unshare(Long photoId, String email); - Page listPublic(int page, int size); - Page listPrivatePhotos(String email, int page, int size); - Page listPublicPhotos(String email, int page, int size); - Page listSharedWith(String email, int page, int size); - Page listSharedPhotos(String email, int page, int size); + PhotoDTO store(MultipartFile file, String visibilite, String ownerEmail); + PhotoDTO getPhotoById(Long id); + Resource loadAsResource(String uuidFichier); + Page listPublic(int page, int size); + Page listPrivatePhotos(String email, int page, int size); + Page listPublicPhotos(String email, int page, int size); + Page listSharedWith(String email, int page, int size); + Page listSharedPhotos(String email, int page, int size); diff --git a/src/main/java/local/epul4a/fotosharing/service/UtilisateurService.java b/src/main/java/local/epul4a/fotosharing/service/UtilisateurService.java new file mode 100644 index 0000000..bcb4f99 --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/UtilisateurService.java @@ -0,0 +1,8 @@ +package local.epul4a.fotosharing.service; + +import local.epul4a.fotosharing.dto.UtilisateurDTO; + +public interface UtilisateurService { + UtilisateurDTO findByEmail(String email); + boolean existsByEmail(String email); +} diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.java index bb9b5b2..e7b6e80 100644 --- a/src/main/java/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.java +++ b/src/main/java/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.java @@ -1,5 +1,7 @@ package local.epul4a.fotosharing.service.impl; +import local.epul4a.fotosharing.dto.CommentaireDTO; +import local.epul4a.fotosharing.mapper.CommentaireMapper; import local.epul4a.fotosharing.model.Commentaire; import local.epul4a.fotosharing.model.Photo; import local.epul4a.fotosharing.model.Utilisateur; @@ -51,9 +53,14 @@ public class CommentaireServiceImpl implements CommentaireService { commentaireRepository.save(c); } @Override - public Page listByPhoto(Long photoId, int page, int size) { + public Page listByPhoto(Long photoId, int page, int size) { Pageable pageable = PageRequest.of(page, size); - return commentaireRepository.findByPhoto_Id(photoId, pageable); + + Page commentaires = + commentaireRepository.findByPhoto_Id(photoId, pageable); + + return commentaires.map(CommentaireMapper::toDTO); } + } diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java new file mode 100644 index 0000000..910e13d --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/impl/PartageServiceImpl.java @@ -0,0 +1,78 @@ +package local.epul4a.fotosharing.service.impl; + +import local.epul4a.fotosharing.dto.PartageDTO; +import local.epul4a.fotosharing.mapper.PartageMapper; +import local.epul4a.fotosharing.model.Partage; +import local.epul4a.fotosharing.model.Photo; +import local.epul4a.fotosharing.model.Utilisateur; +import local.epul4a.fotosharing.repository.PartageRepository; +import local.epul4a.fotosharing.repository.PhotoRepository; +import local.epul4a.fotosharing.repository.UtilisateurRepository; +import local.epul4a.fotosharing.service.PartageService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PartageServiceImpl implements PartageService { + + private final PartageRepository partageRepository; + private final PhotoRepository photoRepository; + private final UtilisateurRepository utilisateurRepository; + + public PartageServiceImpl( + PartageRepository partageRepository, + PhotoRepository photoRepository, + UtilisateurRepository utilisateurRepository + ) { + this.partageRepository = partageRepository; + this.photoRepository = photoRepository; + this.utilisateurRepository = utilisateurRepository; + } + + @Override + public List getPartagesForPhoto(Long photoId) { + return partageRepository.findByPhoto_Id(photoId) + .stream() + .map(PartageMapper::toDTO) + .toList(); + } + + @Override + public void share(Long photoId, String targetEmail, String permissionStr, String ownerEmail) { + + Photo photo = photoRepository.findById(photoId) + .orElseThrow(() -> new RuntimeException("Photo introuvable")); + + if (!photo.getProprietaire().getEmail().equals(ownerEmail)) + throw new RuntimeException("Vous n'êtes pas propriétaire"); + + Utilisateur target = utilisateurRepository.findByEmail(targetEmail) + .orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); + + if (partageRepository.existsByPhoto_IdAndUtilisateur_Email(photoId, targetEmail)) + return; + + Partage.Permission permission = Partage.Permission.valueOf(permissionStr); + + Partage partage = new Partage(); + partage.setPhoto(photo); + partage.setUtilisateur(target); + partage.setPermission(permission); + + partageRepository.save(partage); + } + + @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); + + if (partage != null) + partageRepository.delete(partage); + } +} 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 96166f4..413dfed 100644 --- a/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java +++ b/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java @@ -1,5 +1,7 @@ package local.epul4a.fotosharing.service.impl; +import local.epul4a.fotosharing.dto.PhotoDTO; +import local.epul4a.fotosharing.mapper.PhotoMapper; import local.epul4a.fotosharing.model.Partage; import local.epul4a.fotosharing.model.Photo; import local.epul4a.fotosharing.model.Utilisateur; @@ -8,15 +10,15 @@ import local.epul4a.fotosharing.repository.PhotoRepository; import local.epul4a.fotosharing.repository.UtilisateurRepository; import local.epul4a.fotosharing.service.PhotoService; import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.data.domain.*; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.net.MalformedURLException; import java.nio.file.*; import java.time.LocalDateTime; import java.util.List; @@ -27,134 +29,130 @@ public class PhotoServiceImpl implements PhotoService { @Value("${file.upload-dir}") private String uploadDir; - private final PhotoRepository photoRepository; private final UtilisateurRepository utilisateurRepository; private final PartageRepository partageRepository; - public PhotoServiceImpl(PhotoRepository photoRepository, UtilisateurRepository utilisateurRepository, PartageRepository partageRepository) { + public PhotoServiceImpl( + PhotoRepository photoRepository, + UtilisateurRepository utilisateurRepository, + PartageRepository partageRepository) { this.photoRepository = photoRepository; this.utilisateurRepository = utilisateurRepository; this.partageRepository = partageRepository; } + + //============= STORE PHOTO ============================= @Override - public Photo store(MultipartFile file, String visibilite, String ownerEmail) throws IOException { - if (file.isEmpty()) throw new IOException("Fichier vide"); - - // Vérifier taille / type si besoin (ici basique) - String original = StringUtils.cleanPath(file.getOriginalFilename()); - String uuid = UUID.randomUUID().toString() + "-" + original; - - Path uploadPath = Paths.get(uploadDir); - if (!Files.exists(uploadPath)) Files.createDirectories(uploadPath); - - Path target = uploadPath.resolve(uuid); - Files.copy(file.getInputStream(), target, StandardCopyOption.REPLACE_EXISTING); - - Photo p = new Photo(); - p.setNomFichierOriginal(original); - p.setUuidFichier(uuid); - p.setDateUpload(LocalDateTime.now()); - p.setVisibilite(Photo.Visibilite.valueOf(visibilite)); - Utilisateur u = utilisateurRepository.findByEmail(ownerEmail).orElseThrow(() -> new IOException("Utilisateur introuvable")); - p.setProprietaire(u); - - return photoRepository.save(p); + public PhotoDTO store(MultipartFile file, String visibilite, String ownerEmail) { + try { + if (file.isEmpty()) throw new IOException("Fichier vide"); + String original = StringUtils.cleanPath(file.getOriginalFilename()); + String uuid = UUID.randomUUID() + "-" + original; + Path uploadPath = Paths.get(uploadDir); + if (!Files.exists(uploadPath)) + Files.createDirectories(uploadPath); + Files.copy(file.getInputStream(), + uploadPath.resolve(uuid), + StandardCopyOption.REPLACE_EXISTING); + Utilisateur owner = utilisateurRepository.findByEmail(ownerEmail) + .orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); + Photo p = new Photo(); + p.setNomFichierOriginal(original); + p.setUuidFichier(uuid); + p.setVisibilite(Photo.Visibilite.valueOf(visibilite)); + p.setDateUpload(LocalDateTime.now()); + p.setProprietaire(owner); + return PhotoMapper.toDTO(photoRepository.save(p)); + } catch (Exception ex) { + throw new RuntimeException("Erreur upload : " + ex.getMessage(), ex); + } } - @Override - public Path loadAsPath(String uuidFile) { - return Paths.get(uploadDir).resolve(uuidFile); - } - @Override - public List listByOwner(String email) { - return photoRepository.findByProprietaire_Email(email); - } + //============= GET PHOTO BY ID ========================== @Override - public List listPublicPhotos() { - return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC); - } - - @Override - public List listSharedWith(String email) { - List partages = partageRepository.findByUtilisateur_Email(email); - - return partages.stream() - .map(Partage::getPhoto) - .toList(); - } - - @Override - public List listPrivatePhotos(String email) { - return photoRepository.findByProprietaire_Email(email).stream() - .filter(p -> p.getVisibilite() == Photo.Visibilite.PRIVATE) - .toList(); - } - - @Override - public List listPublicPhotos(String email) { - return photoRepository.findByProprietaire_Email(email).stream() - .filter(p -> p.getVisibilite() == Photo.Visibilite.PUBLIC) - .toList(); - } - - @Override - public void unshare(Long photoId, String email) { - Partage p = partageRepository.findByPhoto_Id(photoId).stream() - .filter(x -> x.getUtilisateur().getEmail().equals(email)) - .findFirst() + public PhotoDTO getPhotoById(Long id) { + return photoRepository.findById(id) + .map(PhotoMapper::toDTO) .orElse(null); - if (p != null) partageRepository.delete(p); } + + + //============= LOAD RESOURCE ============================ @Override - public Page listPublic(int page, int size) { + public Resource loadAsResource(String uuidFichier) { + try { + Path file = Paths.get(uploadDir).resolve(uuidFichier); + Resource resource = new UrlResource(file.toUri()); + if (!resource.exists() || !resource.isReadable()) + throw new RuntimeException("Impossible de lire le fichier : " + uuidFichier); + return resource; + } catch (MalformedURLException e) { + throw new RuntimeException("Fichier introuvable : " + uuidFichier); + } + } + + + + //============= LIST PUBLIC PHOTOS ======================= + @Override + public Page listPublic(int page, int size) { Pageable pageable = PageRequest.of(page, size); - return photoRepository.findByVisibilite(Photo.Visibilite.PUBLIC, pageable); + return photoRepository + .findByVisibilite(Photo.Visibilite.PUBLIC, pageable) + .map(PhotoMapper::toDTO); } + + + //============= PRIVATE PHOTOS OF USER =================== @Override - public Page listPrivatePhotos(String email, int page, int size) { + public Page listPrivatePhotos(String email, int page, int size) { Pageable pageable = PageRequest.of(page, size); - return photoRepository.findByProprietaire_EmailAndVisibilite( - email, - Photo.Visibilite.PRIVATE, - pageable - ); + return photoRepository + .findByProprietaire_EmailAndVisibilite(email, Photo.Visibilite.PRIVATE, pageable) + .map(PhotoMapper::toDTO); } + + + //============= PUBLIC PHOTOS OF USER ==================== @Override - public Page listPublicPhotos(String email, int page, int size) { + public Page listPublicPhotos(String email, int page, int size) { Pageable pageable = PageRequest.of(page, size); - return photoRepository.findByProprietaire_EmailAndVisibilite( - email, - Photo.Visibilite.PUBLIC, - pageable - ); + return photoRepository + .findByProprietaire_EmailAndVisibilite(email, Photo.Visibilite.PUBLIC, pageable) + .map(PhotoMapper::toDTO); } + + + //============= PHOTOS SHARED WITH USER ================== @Override - public Page listSharedWith(String email, int page, int size) { - List partages = partageRepository.findByUtilisateur_Email(email); - List photos = partages.stream().map(Partage::getPhoto).toList(); - // convertir list en page manuellement + public Page listSharedWith(String email, int page, int size) { + List photos = + partageRepository.findByUtilisateur_Email(email) + .stream() + .map(Partage::getPhoto) + .map(PhotoMapper::toDTO) + .toList(); int start = page * size; int end = Math.min(start + size, photos.size()); - List sublist = photos.subList(start, end); - return new PageImpl<>(sublist, PageRequest.of(page, size), photos.size()); + List sub = photos.subList(start, end); + return new PageImpl<>(sub, PageRequest.of(page, size), photos.size()); } + + //============= PHOTOS SET AS SHARED BY USER ============= @Override - public Page listSharedPhotos(String email, int page, int size) { + public Page listSharedPhotos(String email, int page, int size) { Pageable pageable = PageRequest.of(page, size); - return photoRepository.findByProprietaire_EmailAndVisibilite( - email, - Photo.Visibilite.SHARED, - pageable - ); + return photoRepository + .findByProprietaire_EmailAndVisibilite(email, Photo.Visibilite.SHARED, pageable) + .map(PhotoMapper::toDTO); } - -} +} \ No newline at end of file diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.java new file mode 100644 index 0000000..775df1b --- /dev/null +++ b/src/main/java/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.java @@ -0,0 +1,30 @@ +package local.epul4a.fotosharing.service.impl; + +import local.epul4a.fotosharing.dto.UtilisateurDTO; +import local.epul4a.fotosharing.mapper.UtilisateurMapper; +import local.epul4a.fotosharing.model.Utilisateur; +import local.epul4a.fotosharing.repository.UtilisateurRepository; +import local.epul4a.fotosharing.service.UtilisateurService; +import org.springframework.stereotype.Service; + +@Service +public class UtilisateurServiceImpl implements UtilisateurService { + + private final UtilisateurRepository utilisateurRepository; + + public UtilisateurServiceImpl(UtilisateurRepository utilisateurRepository) { + this.utilisateurRepository = utilisateurRepository; + } + + @Override + public UtilisateurDTO findByEmail(String email) { + Utilisateur u = utilisateurRepository.findByEmail(email) + .orElse(null); + return UtilisateurMapper.toDTO(u); + } + + @Override + public boolean existsByEmail(String email) { + return utilisateurRepository.findByEmail(email).isPresent(); + } +} diff --git a/src/main/resources/templates/mes-photos.html b/src/main/resources/templates/mes-photos.html index 8610353..11329f4 100644 --- a/src/main/resources/templates/mes-photos.html +++ b/src/main/resources/templates/mes-photos.html @@ -8,9 +8,6 @@

Mes photos

Uploader une photo

Retour accueil

-
-

Vous n'avez pas encore de photos.

-

Mes photos privées

+ th:href="@{/mes-photos( + pagePrivees=${pagePrivees}, + pagePubliques=${pagePubliques}, + pagePartagees=${pagePartagees}, + pageMesPartagees=${pageMesPartagees - 1} + )}">⬅ + th:href="@{/mes-photos( + pagePrivees=${pagePrivees}, + pagePubliques=${pagePubliques}, + pagePartagees=${pagePartagees}, + pageMesPartagees=${pageMesPartagees + 1} + )}">➡ +
diff --git a/src/main/resources/templates/photo-detail.html b/src/main/resources/templates/photo-detail.html index 7ad65a6..fa57d9d 100644 --- a/src/main/resources/templates/photo-detail.html +++ b/src/main/resources/templates/photo-detail.html @@ -34,6 +34,8 @@
  • + — + Retirer
  • @@ -43,6 +45,12 @@
    + +
diff --git a/target/classes/local/epul4a/fotosharing/controller/PhotoController.class b/target/classes/local/epul4a/fotosharing/controller/PhotoController.class index 341b172..c6787a5 100644 Binary files a/target/classes/local/epul4a/fotosharing/controller/PhotoController.class and b/target/classes/local/epul4a/fotosharing/controller/PhotoController.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/CommentaireDTO.class b/target/classes/local/epul4a/fotosharing/dto/CommentaireDTO.class new file mode 100644 index 0000000..0aba19c Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/dto/CommentaireDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class b/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class new file mode 100644 index 0000000..3537079 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/dto/PartageDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/PhotoDTO.class b/target/classes/local/epul4a/fotosharing/dto/PhotoDTO.class new file mode 100644 index 0000000..d977d06 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/dto/PhotoDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/dto/UtilisateurDTO.class b/target/classes/local/epul4a/fotosharing/dto/UtilisateurDTO.class new file mode 100644 index 0000000..139a13c Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/dto/UtilisateurDTO.class differ diff --git a/target/classes/local/epul4a/fotosharing/mapper/CommentaireMapper.class b/target/classes/local/epul4a/fotosharing/mapper/CommentaireMapper.class new file mode 100644 index 0000000..a453fa7 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/mapper/CommentaireMapper.class differ diff --git a/target/classes/local/epul4a/fotosharing/mapper/PartageMapper.class b/target/classes/local/epul4a/fotosharing/mapper/PartageMapper.class new file mode 100644 index 0000000..cbf2e4c Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/mapper/PartageMapper.class differ diff --git a/target/classes/local/epul4a/fotosharing/mapper/PhotoMapper.class b/target/classes/local/epul4a/fotosharing/mapper/PhotoMapper.class new file mode 100644 index 0000000..4c56109 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/mapper/PhotoMapper.class differ diff --git a/target/classes/local/epul4a/fotosharing/mapper/UtilisateurMapper.class b/target/classes/local/epul4a/fotosharing/mapper/UtilisateurMapper.class new file mode 100644 index 0000000..1f82b7b Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/mapper/UtilisateurMapper.class differ diff --git a/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class b/target/classes/local/epul4a/fotosharing/model/Partage$Permission.class new file mode 100644 index 0000000..79e7c8d Binary files /dev/null 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 a31deba..3315188 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/service/CommentaireService.class b/target/classes/local/epul4a/fotosharing/service/CommentaireService.class index a5c9458..c66c185 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/CommentaireService.class and b/target/classes/local/epul4a/fotosharing/service/CommentaireService.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/PartageService.class b/target/classes/local/epul4a/fotosharing/service/PartageService.class new file mode 100644 index 0000000..cc07511 Binary files /dev/null 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 a22284a..c370058 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/UtilisateurService.class b/target/classes/local/epul4a/fotosharing/service/UtilisateurService.class new file mode 100644 index 0000000..aba2c64 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/service/UtilisateurService.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.class index 8aa0d52..d5db177 100644 Binary files a/target/classes/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.class and b/target/classes/local/epul4a/fotosharing/service/impl/CommentaireServiceImpl.class differ diff --git a/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/PartageServiceImpl.class new file mode 100644 index 0000000..8336e35 Binary files /dev/null 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 68989cf..0cd1326 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/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.class b/target/classes/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.class new file mode 100644 index 0000000..a45d456 Binary files /dev/null and b/target/classes/local/epul4a/fotosharing/service/impl/UtilisateurServiceImpl.class differ diff --git a/target/classes/templates/mes-photos.html b/target/classes/templates/mes-photos.html index 8610353..11329f4 100644 --- a/target/classes/templates/mes-photos.html +++ b/target/classes/templates/mes-photos.html @@ -8,9 +8,6 @@

Mes photos

Uploader une photo

Retour accueil

-
-

Vous n'avez pas encore de photos.

-

Mes photos privées

+ th:href="@{/mes-photos( + pagePrivees=${pagePrivees}, + pagePubliques=${pagePubliques}, + pagePartagees=${pagePartagees}, + pageMesPartagees=${pageMesPartagees - 1} + )}">⬅ + th:href="@{/mes-photos( + pagePrivees=${pagePrivees}, + pagePubliques=${pagePubliques}, + pagePartagees=${pagePartagees}, + pageMesPartagees=${pageMesPartagees + 1} + )}">➡ +
diff --git a/target/classes/templates/photo-detail.html b/target/classes/templates/photo-detail.html index 7ad65a6..fa57d9d 100644 --- a/target/classes/templates/photo-detail.html +++ b/target/classes/templates/photo-detail.html @@ -34,6 +34,8 @@
  • + — + Retirer
  • @@ -43,6 +45,12 @@
    + +