V0.1 de la version public/privé au niveau des dossiers pareents
Some checks failed
Apply PHP CS Fixer / php-cs-fixer (push) Failing after 37s
CI / build-test (push) Successful in 1m40s
rector / Rector (push) Failing after 1m11s

This commit is contained in:
Melaine Gérard 2025-01-24 00:16:16 +01:00
parent 72ee30cc01
commit 3a8fc71eb2
7 changed files with 201 additions and 10 deletions

View File

@ -0,0 +1,2 @@
symfonycasts_tailwind:
binary_version: 'v3.4.17'

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250123225212 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__parent_directory AS SELECT id, name, owner_role FROM parent_directory');
$this->addSql('DROP TABLE parent_directory');
$this->addSql('CREATE TABLE parent_directory (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, owner_role VARCHAR(255) NOT NULL, user_created_id INTEGER NOT NULL, CONSTRAINT FK_B7336B34F987D8A8 FOREIGN KEY (user_created_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO parent_directory (id, name, owner_role) SELECT id, name, owner_role FROM __temp__parent_directory');
$this->addSql('DROP TABLE __temp__parent_directory');
$this->addSql('CREATE INDEX IDX_B7336B34F987D8A8 ON parent_directory (user_created_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__parent_directory AS SELECT id, name, owner_role FROM parent_directory');
$this->addSql('DROP TABLE parent_directory');
$this->addSql('CREATE TABLE parent_directory (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, owner_role VARCHAR(255) NOT NULL)');
$this->addSql('INSERT INTO parent_directory (id, name, owner_role) SELECT id, name, owner_role FROM __temp__parent_directory');
$this->addSql('DROP TABLE __temp__parent_directory');
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250123230226 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE parent_directory ADD COLUMN is_public BOOLEAN NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__parent_directory AS SELECT id, name, owner_role, user_created_id FROM parent_directory');
$this->addSql('DROP TABLE parent_directory');
$this->addSql('CREATE TABLE parent_directory (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, owner_role VARCHAR(255) NOT NULL, user_created_id INTEGER NOT NULL, CONSTRAINT FK_B7336B34F987D8A8 FOREIGN KEY (user_created_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO parent_directory (id, name, owner_role, user_created_id) SELECT id, name, owner_role, user_created_id FROM __temp__parent_directory');
$this->addSql('DROP TABLE __temp__parent_directory');
$this->addSql('CREATE INDEX IDX_B7336B34F987D8A8 ON parent_directory (user_created_id)');
}
}

View File

@ -55,7 +55,9 @@ class FilesController extends AbstractController
throw $this->createNotFoundException("Ce dossier n'existe pas !");
}
if ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true)) {
if (!$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit d'accéder à ce dossier !");
}
}
@ -72,13 +74,13 @@ class FilesController extends AbstractController
if ('' !== $path) {
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $pathFile[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
continue;
}
} elseif ('file' !== $file['type']) {
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $filename]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
continue;
}
}
@ -132,7 +134,7 @@ class FilesController extends AbstractController
*/
$user = $this->getUser();
if ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true)) {
if (!$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit d'accéder à ce fichier !");
}
}
@ -176,7 +178,7 @@ class FilesController extends AbstractController
if (count($realPath) > 1) {
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit de supprimer ce fichier !");
}
}
@ -210,7 +212,7 @@ class FilesController extends AbstractController
$realPath = explode('/', $path);
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit de supprimer ce dossier !");
}
@ -249,7 +251,7 @@ class FilesController extends AbstractController
if (count($realPath) > 1) {
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit de renommer ce fichier !");
}
}
@ -300,7 +302,7 @@ class FilesController extends AbstractController
if (count($realPath) > 1) {
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit de créer de sous-dossier dans ce dossier !");
}
}
@ -338,6 +340,8 @@ class FilesController extends AbstractController
$parentDirectory = new ParentDirectory();
$parentDirectory->setName($name);
$parentDirectory->setOwnerRole($user->getFolderRole());
$parentDirectory->setIsPublic(false);
$parentDirectory->setUserCreated($user);
$this->entityManager->persist($parentDirectory);
$this->entityManager->flush();
@ -372,7 +376,7 @@ class FilesController extends AbstractController
$realPath = explode('/', $filepath);
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit de renommer ce dossier !");
}
@ -431,7 +435,7 @@ class FilesController extends AbstractController
$realPath = explode('/', $path);
$parentDir = $this->parentDirectoryRepository->findOneBy(['name' => $realPath[0]]);
if (null === $parentDir || ($parentDir->getOwnerRole() !== $user->getFolderRole() && !in_array($user->getFolderRole(), $parentDir->getOwnerRole()->getHigherRoles(), true))) {
if (null === $parentDir || !$this->isGranted('file', $parentDir)) {
throw $this->createNotFoundException("Vous n'avez pas le droit d'uploader des fichiers dans ce dossier !");
}

View File

@ -22,6 +22,13 @@ class ParentDirectory
#[ORM\Column(enumType: RoleEnum::class)]
private ?RoleEnum $ownerRole = null;
#[ORM\ManyToOne(inversedBy: 'parentDirectories')]
#[ORM\JoinColumn(nullable: false)]
private ?User $userCreated = null;
#[ORM\Column]
private ?bool $isPublic = null;
public function getId(): ?int
{
return $this->id;
@ -50,4 +57,28 @@ class ParentDirectory
return $this;
}
public function getUserCreated(): ?User
{
return $this->userCreated;
}
public function setUserCreated(?User $userCreated): static
{
$this->userCreated = $userCreated;
return $this;
}
public function isPublic(): ?bool
{
return $this->isPublic;
}
public function setIsPublic(bool $isPublic): static
{
$this->isPublic = $isPublic;
return $this;
}
}

View File

@ -6,6 +6,8 @@ namespace App\Entity;
use App\Enum\RoleEnum;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
@ -44,6 +46,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(length: 255)]
private ?string $fullname = null;
/**
* @var Collection<int, ParentDirectory>
*/
#[ORM\OneToMany(targetEntity: ParentDirectory::class, mappedBy: 'userCreated')]
private Collection $parentDirectories;
public function __construct()
{
$this->parentDirectories = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
@ -142,4 +155,32 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
/**
* @return Collection<int, ParentDirectory>
*/
public function getParentDirectories(): Collection
{
return $this->parentDirectories;
}
public function addParentDirectory(ParentDirectory $parentDirectory): static
{
if (!$this->parentDirectories->contains($parentDirectory)) {
$this->parentDirectories->add($parentDirectory);
$parentDirectory->setUserCreated($this);
}
return $this;
}
public function removeParentDirectory(ParentDirectory $parentDirectory): static
{
// set the owning side to null (unless already changed)
if ($this->parentDirectories->removeElement($parentDirectory) && $parentDirectory->getUserCreated() === $this) {
$parentDirectory->setUserCreated(null);
}
return $this;
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace App\Security\Voter;
use App\Entity\ParentDirectory;
use App\Entity\User;
use App\Enum\RoleEnum;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
final class FileVoter extends Voter
{
protected function supports(string $attribute, mixed $subject): bool
{
return $subject instanceof ParentDirectory;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
/**
* @var ParentDirectory $realSubject
*/
$realSubject = $subject;
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
if ($realSubject->getUserCreated() === $user) {
return true;
}
return $realSubject->isPublic() && ($realSubject->getOwnerRole() === $user->getFolderRole() || in_array($user->getFolderRole(), $realSubject->getOwnerRole()->getHigherRoles(), true));
}
}