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);
|
||||
|
||||
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("partages",
|
||||
@@ -181,6 +186,7 @@ public class PhotoController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/photo/{id}/unshare/{email}")
|
||||
public String unshare(@PathVariable Long id, @PathVariable String email) {
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package local.epul4a.fotosharing.repository;
|
||||
|
||||
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 java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PartageRepository extends JpaRepository<Partage, Long> {
|
||||
// liste des partages pour une photo
|
||||
|
||||
List<Partage> findByPhoto_Id(Long photoId);
|
||||
// vérifier si un utilisateur a accès partagé
|
||||
boolean existsByPhoto_IdAndUtilisateur_Email(Long photoId, 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;
|
||||
|
||||
import local.epul4a.fotosharing.model.Photo;
|
||||
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 local.epul4a.fotosharing.service.PartageService;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("securityService")
|
||||
public class SecurityService {
|
||||
|
||||
private final PhotoRepository photoRepository;
|
||||
private final PartageRepository partageRepository;
|
||||
|
||||
public SecurityService(PhotoRepository photoRepository, PartageRepository partageRepository) {
|
||||
this.photoRepository = photoRepository;
|
||||
this.partageRepository = partageRepository;
|
||||
private final PartageService partageService;
|
||||
public SecurityService(PartageService partageService) {
|
||||
this.partageService = partageService;
|
||||
}
|
||||
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
String email = authentication.getName();
|
||||
// Propriétaire → OK
|
||||
if (photo.getProprietaire().getEmail().equals(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;
|
||||
// Vérification basée sur les ACL (READ / COMMENT / ADMIN)
|
||||
return partageService.canView(photoId, email);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package local.epul4a.fotosharing.service;
|
||||
|
||||
import local.epul4a.fotosharing.dto.PartageDTO;
|
||||
import local.epul4a.fotosharing.model.Partage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PartageService {
|
||||
void share(Long photoId, String targetEmail, String permission, String ownerEmail);
|
||||
void unshare(Long photoId, String targetEmail);
|
||||
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)
|
||||
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 -->
|
||||
<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>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||
@@ -34,31 +35,35 @@
|
||||
<ul>
|
||||
<li th:each="p : ${partages}">
|
||||
<span th:text="${p.utilisateur.email}"></span>
|
||||
—
|
||||
<span th:text="${p.permission}"></span>
|
||||
<a th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||
style="color:red;">Retirer</a>
|
||||
<span> - <b th:text="${p.permission}"></b></span>
|
||||
<!-- ADMIN OU PROPRIÉTAIRE : peut retirer -->
|
||||
<a th:if="${canAdmin}"
|
||||
th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||
style="color:red; margin-left:10px;">Retirer</a>
|
||||
</li>
|
||||
</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">
|
||||
<label>Email de l'utilisateur :</label>
|
||||
<input type="email" name="email" required />
|
||||
<label>Permission :</label>
|
||||
<select name="permission">
|
||||
<option value="READ">Lecture</option>
|
||||
<option value="COMMENT">Commenter</option>
|
||||
<option value="ADMIN">Administrer</option>
|
||||
<option value="READ">Lecture seule</option>
|
||||
<option value="COMMENT">Commentaire autorisé</option>
|
||||
<option value="ADMIN">Administrateur</option>
|
||||
</select>
|
||||
<button type="submit">Partager</button>
|
||||
</form>
|
||||
</div>
|
||||
<div th:if="${currentUser != photo.proprietaire.email}">
|
||||
<em>Seul le propriétaire peut partager cette photo.</em>
|
||||
<div th:if="${!canAdmin}">
|
||||
<em>Vous n’avez pas les droits de gestion du partage.</em>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Commentaires -->
|
||||
<h2>Commentaires</h2>
|
||||
<div th:each="c : ${commentairesPage.content}">
|
||||
@@ -76,17 +81,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Formulaire d'ajout de commentaire -->
|
||||
<div th:if="${currentUser}">
|
||||
<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>
|
||||
|
||||
<!-- Si pas connecté -->
|
||||
<div th:if="${currentUser == null}">
|
||||
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||
</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>
|
||||
<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 -->
|
||||
<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>Date upload :</strong> <span th:text="${photo.dateUpload}"></span></li>
|
||||
<li><strong>Visibilité :</strong> <span th:text="${photo.visibilite}"></span></li>
|
||||
@@ -34,31 +35,35 @@
|
||||
<ul>
|
||||
<li th:each="p : ${partages}">
|
||||
<span th:text="${p.utilisateur.email}"></span>
|
||||
—
|
||||
<span th:text="${p.permission}"></span>
|
||||
<a th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||
style="color:red;">Retirer</a>
|
||||
<span> - <b th:text="${p.permission}"></b></span>
|
||||
<!-- ADMIN OU PROPRIÉTAIRE : peut retirer -->
|
||||
<a th:if="${canAdmin}"
|
||||
th:href="@{'/photo/' + ${photo.id} + '/unshare/' + ${p.utilisateur.email}}"
|
||||
style="color:red; margin-left:10px;">Retirer</a>
|
||||
</li>
|
||||
</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">
|
||||
<label>Email de l'utilisateur :</label>
|
||||
<input type="email" name="email" required />
|
||||
<label>Permission :</label>
|
||||
<select name="permission">
|
||||
<option value="READ">Lecture</option>
|
||||
<option value="COMMENT">Commenter</option>
|
||||
<option value="ADMIN">Administrer</option>
|
||||
<option value="READ">Lecture seule</option>
|
||||
<option value="COMMENT">Commentaire autorisé</option>
|
||||
<option value="ADMIN">Administrateur</option>
|
||||
</select>
|
||||
<button type="submit">Partager</button>
|
||||
</form>
|
||||
</div>
|
||||
<div th:if="${currentUser != photo.proprietaire.email}">
|
||||
<em>Seul le propriétaire peut partager cette photo.</em>
|
||||
<div th:if="${!canAdmin}">
|
||||
<em>Vous n’avez pas les droits de gestion du partage.</em>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Commentaires -->
|
||||
<h2>Commentaires</h2>
|
||||
<div th:each="c : ${commentairesPage.content}">
|
||||
@@ -76,17 +81,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Formulaire d'ajout de commentaire -->
|
||||
<div th:if="${currentUser}">
|
||||
<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>
|
||||
|
||||
<!-- Si pas connecté -->
|
||||
<div th:if="${currentUser == null}">
|
||||
<p><a th:href="@{/login}">Connectez-vous</a> pour commenter.</p>
|
||||
</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>
|
||||
<a th:href="@{'/photo/' + ${photo.id} + '/raw'}" target="_blank">Voir en grande taille</a>
|
||||
|
||||
Reference in New Issue
Block a user