FEAT : Ajout du mécanisme READ, COMMENT et ADMIN pour les photos à partager
This commit is contained in:
@@ -148,6 +148,11 @@ public class PhotoController {
|
|||||||
model.addAttribute("currentPage", page);
|
model.addAttribute("currentPage", page);
|
||||||
|
|
||||||
String currentUser = (auth != null ? auth.getName() : null);
|
String currentUser = (auth != null ? auth.getName() : null);
|
||||||
|
boolean canComment = partageService.canComment(id, currentUser);
|
||||||
|
boolean canAdmin = partageService.canAdmin(id, currentUser);
|
||||||
|
|
||||||
|
model.addAttribute("canComment", canComment);
|
||||||
|
model.addAttribute("canAdmin", canAdmin);
|
||||||
model.addAttribute("currentUser", currentUser);
|
model.addAttribute("currentUser", currentUser);
|
||||||
|
|
||||||
model.addAttribute("partages",
|
model.addAttribute("partages",
|
||||||
@@ -181,6 +186,7 @@ public class PhotoController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/photo/{id}/unshare/{email}")
|
@GetMapping("/photo/{id}/unshare/{email}")
|
||||||
public String unshare(@PathVariable Long id, @PathVariable String email) {
|
public String unshare(@PathVariable Long id, @PathVariable String email) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
package local.epul4a.fotosharing.repository;
|
package local.epul4a.fotosharing.repository;
|
||||||
|
|
||||||
import local.epul4a.fotosharing.model.Partage;
|
import local.epul4a.fotosharing.model.Partage;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface PartageRepository extends JpaRepository<Partage, Long> {
|
public interface PartageRepository extends JpaRepository<Partage, Long> {
|
||||||
// liste des partages pour une photo
|
|
||||||
List<Partage> findByPhoto_Id(Long photoId);
|
List<Partage> findByPhoto_Id(Long photoId);
|
||||||
// vérifier si un utilisateur a accès partagé
|
|
||||||
boolean existsByPhoto_IdAndUtilisateur_Email(Long photoId, String email);
|
boolean existsByPhoto_IdAndUtilisateur_Email(Long photoId, String email);
|
||||||
List<Partage> findByUtilisateur_Email(String email);
|
List<Partage> findByUtilisateur_Email(String email);
|
||||||
|
Optional<Partage> findByPhoto_IdAndUtilisateur_Email(Long photoId, String email);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,23 @@
|
|||||||
package local.epul4a.fotosharing.security;
|
package local.epul4a.fotosharing.security;
|
||||||
|
|
||||||
import local.epul4a.fotosharing.model.Photo;
|
import local.epul4a.fotosharing.service.PartageService;
|
||||||
import local.epul4a.fotosharing.repository.PartageRepository;
|
|
||||||
import local.epul4a.fotosharing.repository.PhotoRepository;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.naming.ldap.PagedResultsControl;
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service("securityService")
|
@Service("securityService")
|
||||||
public class SecurityService {
|
public class SecurityService {
|
||||||
|
|
||||||
private final PhotoRepository photoRepository;
|
private final PartageService partageService;
|
||||||
private final PartageRepository partageRepository;
|
public SecurityService(PartageService partageService) {
|
||||||
|
this.partageService = partageService;
|
||||||
public SecurityService(PhotoRepository photoRepository, PartageRepository partageRepository) {
|
|
||||||
this.photoRepository = photoRepository;
|
|
||||||
this.partageRepository = partageRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canAccessPhoto(Authentication authentication, Long photoId) {
|
public boolean canAccessPhoto(Authentication authentication, Long photoId) {
|
||||||
Photo photo = photoRepository.findById(photoId).orElse(null);
|
|
||||||
if (photo == null) return false;
|
|
||||||
// PUBLIC → accès total
|
|
||||||
if (photo.getVisibilite() == Photo.Visibilite.PUBLIC) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Pas connecté → rejeter tout sauf PUBLIC
|
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String email = authentication.getName();
|
String email = authentication.getName();
|
||||||
// Propriétaire → OK
|
// Vérification basée sur les ACL (READ / COMMENT / ADMIN)
|
||||||
if (photo.getProprietaire().getEmail().equals(email)) {
|
return partageService.canView(photoId, email);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// SHARED → vérifier dans la table PARTAGE
|
|
||||||
if (photo.getVisibilite() == Photo.Visibilite.SHARED) {
|
|
||||||
return partageRepository.existsByPhoto_IdAndUtilisateur_Email(photoId, email);
|
|
||||||
}
|
|
||||||
// PRIVATE par défaut → refus
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
package local.epul4a.fotosharing.service;
|
package local.epul4a.fotosharing.service;
|
||||||
|
|
||||||
import local.epul4a.fotosharing.dto.PartageDTO;
|
import local.epul4a.fotosharing.dto.PartageDTO;
|
||||||
|
import local.epul4a.fotosharing.model.Partage;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface PartageService {
|
public interface PartageService {
|
||||||
void share(Long photoId, String targetEmail, String permission, String ownerEmail);
|
void share(Long photoId, String targetEmail, String permission, String ownerEmail);
|
||||||
void unshare(Long photoId, String targetEmail);
|
void unshare(Long photoId, String targetEmail);
|
||||||
List<PartageDTO> getPartagesForPhoto(Long photoId);
|
List<PartageDTO> getPartagesForPhoto(Long photoId);
|
||||||
|
boolean canView(Long photoId, String email);
|
||||||
|
boolean canComment(Long photoId, String email);
|
||||||
|
boolean canAdmin(Long photoId, String email);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,4 +75,50 @@ public class PartageServiceImpl implements PartageService {
|
|||||||
if (partage != null)
|
if (partage != null)
|
||||||
partageRepository.delete(partage);
|
partageRepository.delete(partage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canView(Long photoId, String email) {
|
||||||
|
Photo photo = photoRepository.findById(photoId).orElse(null);
|
||||||
|
if (photo == null) return false;
|
||||||
|
// Propriétaire => accès total
|
||||||
|
if (photo.getProprietaire().getEmail().equals(email))
|
||||||
|
return true;
|
||||||
|
// 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);
|
||||||
|
return partage != null; // READ / COMMENT / ADMIN
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canComment(Long photoId, String email) {
|
||||||
|
Photo photo = photoRepository.findById(photoId).orElse(null);
|
||||||
|
if (photo == null) return false;
|
||||||
|
// propriétaire = admin total
|
||||||
|
if (photo.getProprietaire().getEmail().equals(email))
|
||||||
|
return true;
|
||||||
|
Partage partage = partageRepository
|
||||||
|
.findByPhoto_IdAndUtilisateur_Email(photoId, email)
|
||||||
|
.orElse(null);
|
||||||
|
if (partage == null) return false;
|
||||||
|
return partage.getPermission() == Partage.Permission.COMMENT
|
||||||
|
|| partage.getPermission() == Partage.Permission.ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAdmin(Long photoId, String email) {
|
||||||
|
Photo photo = photoRepository.findById(photoId).orElse(null);
|
||||||
|
if (photo == null) return false;
|
||||||
|
// propriétaire = admin total
|
||||||
|
if (photo.getProprietaire().getEmail().equals(email))
|
||||||
|
return true;
|
||||||
|
Partage partage = partageRepository
|
||||||
|
.findByPhoto_IdAndUtilisateur_Email(photoId, email)
|
||||||
|
.orElse(null);
|
||||||
|
if (partage == null) return false;
|
||||||
|
return partage.getPermission() == Partage.Permission.ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
<!-- Infos -->
|
<!-- Infos -->
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><strong>Votre rôle :</strong><span th:text="${photo.proprietaire.email == currentUser ? 'Propriétaire' : (canAdmin ? 'Admin' : (canComment ? 'Commentateur' : 'Lecteur'))}"></span></li>
|
||||||
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
||||||
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||||
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||||
@@ -34,31 +35,35 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li th:each="p : ${partages}">
|
<li th:each="p : ${partages}">
|
||||||
<span th:text="${p.utilisateur.email}"></span>
|
<span th:text="${p.utilisateur.email}"></span>
|
||||||
—
|
<span> - <b th:text="${p.permission}"></b></span>
|
||||||
<span th:text="${p.permission}"></span>
|
<!-- ADMIN OU PROPRIÉTAIRE : peut retirer -->
|
||||||
<a th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
<a th:if="${canAdmin}"
|
||||||
style="color:red;">Retirer</a>
|
th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||||
|
style="color:red; margin-left:10px;">Retirer</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Partager la photo</h2>
|
|
||||||
<div th:if="${currentUser == photo.proprietaire.email}">
|
<!-- Formulaire d’ajout visible uniquement en ADMIN ou PROPRIÉTAIRE -->
|
||||||
|
<div th:if="${canAdmin}">
|
||||||
|
<h3>Partager la photo</h3>
|
||||||
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
||||||
<label>Email de l'utilisateur :</label>
|
<label>Email de l'utilisateur :</label>
|
||||||
<input type="email" name="email" required />
|
<input type="email" name="email" required />
|
||||||
<label>Permission :</label>
|
<label>Permission :</label>
|
||||||
<select name="permission">
|
<select name="permission">
|
||||||
<option value="READ">Lecture</option>
|
<option value="READ">Lecture seule</option>
|
||||||
<option value="COMMENT">Commenter</option>
|
<option value="COMMENT">Commentaire autorisé</option>
|
||||||
<option value="ADMIN">Administrer</option>
|
<option value="ADMIN">Administrateur</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="submit">Partager</button>
|
<button type="submit">Partager</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${currentUser != photo.proprietaire.email}">
|
<div th:if="${!canAdmin}">
|
||||||
<em>Seul le propriétaire peut partager cette photo.</em>
|
<em>Vous n’avez pas les droits de gestion du partage.</em>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Commentaires -->
|
<!-- Commentaires -->
|
||||||
<h2>Commentaires</h2>
|
<h2>Commentaires</h2>
|
||||||
<div th:each="c : ${commentairesPage.content}">
|
<div th:each="c : ${commentairesPage.content}">
|
||||||
@@ -76,17 +81,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Formulaire d'ajout de commentaire -->
|
<!-- Formulaire d'ajout de commentaire -->
|
||||||
<div th:if="${currentUser}">
|
<!-- Si pas connecté -->
|
||||||
<h3>Ajouter un commentaire</h3>
|
|
||||||
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
|
||||||
<textarea name="contenu" rows="3" cols="50"></textarea><br/>
|
|
||||||
<button type="submit">Envoyer</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:if="${currentUser == null}">
|
<div th:if="${currentUser == null}">
|
||||||
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Si connecté mais pas autorisé -->
|
||||||
|
<div th:if="${currentUser != null and !canComment}">
|
||||||
|
<em>Vous pouvez consulter cette photo, mais pas commenter.</em>
|
||||||
|
</div>
|
||||||
|
<!-- Si COMMENT ou ADMIN ou PROPRIÉTAIRE -->
|
||||||
|
<div th:if="${canComment}">
|
||||||
|
<h3>Ajouter un commentaire</h3>
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
||||||
|
<textarea name="contenu" rows="3" cols="50" required></textarea><br/>
|
||||||
|
<button type="submit">Envoyer</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
<!-- Infos -->
|
<!-- Infos -->
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><strong>Votre rôle :</strong><span th:text="${photo.proprietaire.email == currentUser ? 'Propriétaire' : (canAdmin ? 'Admin' : (canComment ? 'Commentateur' : 'Lecteur'))}"></span></li>
|
||||||
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
<li><strong>Nom original :</strong> <span th:text="${photo.nomFichierOriginal}"></span></li>
|
||||||
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
<li><strong>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||||
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||||
@@ -34,31 +35,35 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li th:each="p : ${partages}">
|
<li th:each="p : ${partages}">
|
||||||
<span th:text="${p.utilisateur.email}"></span>
|
<span th:text="${p.utilisateur.email}"></span>
|
||||||
—
|
<span> - <b th:text="${p.permission}"></b></span>
|
||||||
<span th:text="${p.permission}"></span>
|
<!-- ADMIN OU PROPRIÉTAIRE : peut retirer -->
|
||||||
<a th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
<a th:if="${canAdmin}"
|
||||||
style="color:red;">Retirer</a>
|
th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||||
|
style="color:red; margin-left:10px;">Retirer</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Partager la photo</h2>
|
|
||||||
<div th:if="${currentUser == photo.proprietaire.email}">
|
<!-- Formulaire d’ajout visible uniquement en ADMIN ou PROPRIÉTAIRE -->
|
||||||
|
<div th:if="${canAdmin}">
|
||||||
|
<h3>Partager la photo</h3>
|
||||||
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
<form th:action="@{'/photo/' + ${photo.id} + '/share'}" method="post">
|
||||||
<label>Email de l'utilisateur :</label>
|
<label>Email de l'utilisateur :</label>
|
||||||
<input type="email" name="email" required />
|
<input type="email" name="email" required />
|
||||||
<label>Permission :</label>
|
<label>Permission :</label>
|
||||||
<select name="permission">
|
<select name="permission">
|
||||||
<option value="READ">Lecture</option>
|
<option value="READ">Lecture seule</option>
|
||||||
<option value="COMMENT">Commenter</option>
|
<option value="COMMENT">Commentaire autorisé</option>
|
||||||
<option value="ADMIN">Administrer</option>
|
<option value="ADMIN">Administrateur</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="submit">Partager</button>
|
<button type="submit">Partager</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${currentUser != photo.proprietaire.email}">
|
<div th:if="${!canAdmin}">
|
||||||
<em>Seul le propriétaire peut partager cette photo.</em>
|
<em>Vous n’avez pas les droits de gestion du partage.</em>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Commentaires -->
|
<!-- Commentaires -->
|
||||||
<h2>Commentaires</h2>
|
<h2>Commentaires</h2>
|
||||||
<div th:each="c : ${commentairesPage.content}">
|
<div th:each="c : ${commentairesPage.content}">
|
||||||
@@ -76,17 +81,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Formulaire d'ajout de commentaire -->
|
<!-- Formulaire d'ajout de commentaire -->
|
||||||
<div th:if="${currentUser}">
|
<!-- Si pas connecté -->
|
||||||
<h3>Ajouter un commentaire</h3>
|
|
||||||
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
|
||||||
<textarea name="contenu" rows="3" cols="50"></textarea><br/>
|
|
||||||
<button type="submit">Envoyer</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:if="${currentUser == null}">
|
<div th:if="${currentUser == null}">
|
||||||
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Si connecté mais pas autorisé -->
|
||||||
|
<div th:if="${currentUser != null and !canComment}">
|
||||||
|
<em>Vous pouvez consulter cette photo, mais pas commenter.</em>
|
||||||
|
</div>
|
||||||
|
<!-- Si COMMENT ou ADMIN ou PROPRIÉTAIRE -->
|
||||||
|
<div th:if="${canComment}">
|
||||||
|
<h3>Ajouter un commentaire</h3>
|
||||||
|
<form th:action="@{'/photo/' + ${photo.id} + '/comment'}" method="post">
|
||||||
|
<textarea name="contenu" rows="3" cols="50" required></textarea><br/>
|
||||||
|
<button type="submit">Envoyer</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user