FEAT : upload en local /opt/photo-app/uploads + visualisation photo
This commit is contained in:
@@ -2,6 +2,7 @@ package local.epul4a.fotosharing.controller;
|
||||
|
||||
import local.epul4a.fotosharing.model.Photo;
|
||||
import local.epul4a.fotosharing.model.Utilisateur;
|
||||
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||
import local.epul4a.fotosharing.security.CustomUserDetails;
|
||||
import local.epul4a.fotosharing.service.PhotoService;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -16,15 +17,18 @@ 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;
|
||||
|
||||
@Controller
|
||||
public class PhotoController {
|
||||
|
||||
private final PhotoService photoService;
|
||||
private final PhotoRepository photoRepository;
|
||||
|
||||
public PhotoController(PhotoService photoService) {
|
||||
public PhotoController(PhotoService photoService, PhotoRepository photoRepository) {
|
||||
this.photoService = photoService;
|
||||
this.photoRepository = photoRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/upload")
|
||||
@@ -35,12 +39,13 @@ public class PhotoController {
|
||||
@PostMapping("/upload")
|
||||
public String doUpload(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value="visibilite", defaultValue = "PRIVATE") String visibilite,
|
||||
@AuthenticationPrincipal CustomUserDetails user,
|
||||
Authentication authentication,
|
||||
Model model) {
|
||||
try {
|
||||
Photo p = photoService.store(file, visibilite, user.getUsername());
|
||||
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:/"; // ou page d'affichage
|
||||
return "redirect:/";
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("error", e.getMessage());
|
||||
return "upload";
|
||||
@@ -48,22 +53,38 @@ public class PhotoController {
|
||||
}
|
||||
|
||||
@GetMapping("/photo/{id}/raw")
|
||||
public ResponseEntity<Resource> rawPhoto(@PathVariable("id") String idOrUuid) {
|
||||
// idOrUuid peut être uuid stocké ou id numeric ; ici on assume uuid
|
||||
Path p = photoService.loadAsPath(idOrUuid);
|
||||
public ResponseEntity<Resource> rawPhoto(@PathVariable("id") Long id) {
|
||||
Photo photo = photoRepository.findById(id).orElse(null);
|
||||
if (photo == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
Path p = photoService.loadAsPath(photo.getUuidFichier());
|
||||
Resource r = new PathResource(p);
|
||||
|
||||
if (!r.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
String contentType = "application/octet-stream";
|
||||
try {
|
||||
// tentative de détection basique
|
||||
contentType = java.nio.file.Files.probeContentType(p);
|
||||
contentType = Files.probeContentType(p);
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(contentType != null ? contentType : "application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + p.getFileName().toString() + "\"")
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"inline; filename=\"" + photo.getNomFichierOriginal() + "\"")
|
||||
.body(r);
|
||||
}
|
||||
|
||||
@GetMapping("/mes-photos")
|
||||
public String mesPhotos(Model model, Authentication authentication) {
|
||||
String email = authentication.getName();
|
||||
model.addAttribute("photos", photoService.listByOwner(email));
|
||||
return "mes-photos";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ package local.epul4a.fotosharing.repository;
|
||||
|
||||
import local.epul4a.fotosharing.model.Photo;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.List;
|
||||
|
||||
public interface PhotoRepository extends JpaRepository<Photo, Long> {
|
||||
|
||||
List<Photo> findByProprietaire_Email(String email);
|
||||
}
|
||||
@@ -4,8 +4,11 @@ import local.epul4a.fotosharing.model.Photo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.IOException;
|
||||
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<Photo> listByOwner(String email);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@@ -58,4 +59,9 @@ public class PhotoServiceImpl implements PhotoService {
|
||||
public Path loadAsPath(String uuidFile) {
|
||||
return Paths.get(uploadDir).resolve(uuidFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Photo> listByOwner(String email) {
|
||||
return photoRepository.findByProprietaire_Email(email);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<body>
|
||||
<h1>Bienvenue sur FotoSharing<span th:if="${prenom}" th:text="' : ' + ${prenom}"></span></h1>
|
||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||
<p><a th:href="@{/mes-photos}">Voir mes photos</a></p>
|
||||
<p>
|
||||
<form th:action="@{/logout}" method="post" style="display: inline;">
|
||||
<button type="submit"
|
||||
|
||||
26
src/main/resources/templates/mes-photos.html
Normal file
26
src/main/resources/templates/mes-photos.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Mes photos</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Mes photos</h1>
|
||||
|
||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||
<p><a th:href="@{/}">Retour accueil</a></p>
|
||||
|
||||
<div th:if="${#lists.isEmpty(photos)}">
|
||||
<p>Vous n'avez pas encore de photos.</p>
|
||||
</div>
|
||||
|
||||
<ul th:if="${!#lists.isEmpty(photos)}">
|
||||
<li th:each="p : ${photos}">
|
||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
||||
—
|
||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@
|
||||
<body>
|
||||
<h1>Bienvenue sur FotoSharing<span th:if="${prenom}" th:text="' : ' + ${prenom}"></span></h1>
|
||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||
<p><a th:href="@{/mes-photos}">Voir mes photos</a></p>
|
||||
<p>
|
||||
<form th:action="@{/logout}" method="post" style="display: inline;">
|
||||
<button type="submit"
|
||||
|
||||
26
target/classes/templates/mes-photos.html
Normal file
26
target/classes/templates/mes-photos.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Mes photos</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Mes photos</h1>
|
||||
|
||||
<p><a th:href="@{/upload}">Uploader une photo</a></p>
|
||||
<p><a th:href="@{/}">Retour accueil</a></p>
|
||||
|
||||
<div th:if="${#lists.isEmpty(photos)}">
|
||||
<p>Vous n'avez pas encore de photos.</p>
|
||||
</div>
|
||||
|
||||
<ul th:if="${!#lists.isEmpty(photos)}">
|
||||
<li th:each="p : ${photos}">
|
||||
<span th:text="${p.nomFichierOriginal}">Nom du fichier</span>
|
||||
—
|
||||
<a th:href="@{'/photo/' + ${p.id} + '/raw'}" target="_blank">Voir</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user