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.Photo;
|
||||||
import local.epul4a.fotosharing.model.Utilisateur;
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
import local.epul4a.fotosharing.security.CustomUserDetails;
|
import local.epul4a.fotosharing.security.CustomUserDetails;
|
||||||
import local.epul4a.fotosharing.service.PhotoService;
|
import local.epul4a.fotosharing.service.PhotoService;
|
||||||
import org.springframework.core.io.Resource;
|
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.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class PhotoController {
|
public class PhotoController {
|
||||||
|
|
||||||
private final PhotoService photoService;
|
private final PhotoService photoService;
|
||||||
|
private final PhotoRepository photoRepository;
|
||||||
|
|
||||||
public PhotoController(PhotoService photoService) {
|
public PhotoController(PhotoService photoService, PhotoRepository photoRepository) {
|
||||||
this.photoService = photoService;
|
this.photoService = photoService;
|
||||||
|
this.photoRepository = photoRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/upload")
|
@GetMapping("/upload")
|
||||||
@@ -35,12 +39,13 @@ public class PhotoController {
|
|||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public String doUpload(@RequestParam("file") MultipartFile file,
|
public String doUpload(@RequestParam("file") MultipartFile file,
|
||||||
@RequestParam(value="visibilite", defaultValue = "PRIVATE") String visibilite,
|
@RequestParam(value="visibilite", defaultValue = "PRIVATE") String visibilite,
|
||||||
@AuthenticationPrincipal CustomUserDetails user,
|
Authentication authentication,
|
||||||
Model model) {
|
Model model) {
|
||||||
try {
|
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());
|
model.addAttribute("message", "Upload OK : " + p.getId());
|
||||||
return "redirect:/"; // ou page d'affichage
|
return "redirect:/";
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
model.addAttribute("error", e.getMessage());
|
model.addAttribute("error", e.getMessage());
|
||||||
return "upload";
|
return "upload";
|
||||||
@@ -48,22 +53,38 @@ public class PhotoController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/photo/{id}/raw")
|
@GetMapping("/photo/{id}/raw")
|
||||||
public ResponseEntity<Resource> rawPhoto(@PathVariable("id") String idOrUuid) {
|
public ResponseEntity<Resource> rawPhoto(@PathVariable("id") Long id) {
|
||||||
// idOrUuid peut être uuid stocké ou id numeric ; ici on assume uuid
|
Photo photo = photoRepository.findById(id).orElse(null);
|
||||||
Path p = photoService.loadAsPath(idOrUuid);
|
if (photo == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Path p = photoService.loadAsPath(photo.getUuidFichier());
|
||||||
Resource r = new PathResource(p);
|
Resource r = new PathResource(p);
|
||||||
|
|
||||||
if (!r.exists()) {
|
if (!r.exists()) {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
String contentType = "application/octet-stream";
|
String contentType = "application/octet-stream";
|
||||||
try {
|
try {
|
||||||
// tentative de détection basique
|
contentType = Files.probeContentType(p);
|
||||||
contentType = java.nio.file.Files.probeContentType(p);
|
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.contentType(MediaType.parseMediaType(contentType != null ? contentType : "application/octet-stream"))
|
.contentType(MediaType.parseMediaType(contentType))
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + p.getFileName().toString() + "\"")
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"inline; filename=\"" + photo.getNomFichierOriginal() + "\"")
|
||||||
.body(r);
|
.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 local.epul4a.fotosharing.model.Photo;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface PhotoRepository extends JpaRepository<Photo, Long> {
|
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 org.springframework.web.multipart.MultipartFile;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface PhotoService {
|
public interface PhotoService {
|
||||||
Photo store(MultipartFile file, String visibilite, String ownerEmail) throws IOException;
|
Photo store(MultipartFile file, String visibilite, String ownerEmail) throws IOException;
|
||||||
Path loadAsPath(String uuidFile);
|
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.io.IOException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -58,4 +59,9 @@ public class PhotoServiceImpl implements PhotoService {
|
|||||||
public Path loadAsPath(String uuidFile) {
|
public Path loadAsPath(String uuidFile) {
|
||||||
return Paths.get(uploadDir).resolve(uuidFile);
|
return Paths.get(uploadDir).resolve(uuidFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Photo> listByOwner(String email) {
|
||||||
|
return photoRepository.findByProprietaire_Email(email);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>Bienvenue sur FotoSharing<span th:if="${prenom}" th:text="' : ' + ${prenom}"></span></h1>
|
<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="@{/upload}">Uploader une photo</a></p>
|
||||||
|
<p><a th:href="@{/mes-photos}">Voir mes photos</a></p>
|
||||||
<p>
|
<p>
|
||||||
<form th:action="@{/logout}" method="post" style="display: inline;">
|
<form th:action="@{/logout}" method="post" style="display: inline;">
|
||||||
<button type="submit"
|
<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>
|
<body>
|
||||||
<h1>Bienvenue sur FotoSharing<span th:if="${prenom}" th:text="' : ' + ${prenom}"></span></h1>
|
<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="@{/upload}">Uploader une photo</a></p>
|
||||||
|
<p><a th:href="@{/mes-photos}">Voir mes photos</a></p>
|
||||||
<p>
|
<p>
|
||||||
<form th:action="@{/logout}" method="post" style="display: inline;">
|
<form th:action="@{/logout}" method="post" style="display: inline;">
|
||||||
<button type="submit"
|
<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