Browse Source

add upload requests and file write methods

Olivier Massot 2 years ago
parent
commit
eb0ec9daf3

+ 71 - 0
src/ApiResources/Core/File/UploadRequest.php

@@ -0,0 +1,71 @@
+<?php
+declare (strict_types=1);
+
+namespace App\ApiResources\Core\File;
+
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use App\State\Processor\Core\UploadRequestProcessor;
+use App\State\Provider\Core\DownloadRequestProvider;
+
+/**
+ * A request for a file from the LocalStorage
+ */
+#[ApiResource(
+    operations: [
+        new Post(
+            uriTemplate: '/upload/{fileId}',
+            requirements: ['fileId' => '\\d+'],
+            security: 'is_granted("ROLE_FILE")',
+            processor: UploadRequestProcessor::class
+        ),
+        new Put(
+            uriTemplate: '/upload/{fileId}',
+            requirements: ['fileId' => '\\d+'],
+            security: 'is_granted("ROLE_FILE")',
+            processor: UploadRequestProcessor::class
+        ),
+        new Post(
+            uriTemplate: '/internal/download/{fileId}',
+            requirements: ['fileId' => '\\d+'],
+            processor: UploadRequestProcessor::class
+        ),
+        new Put(
+            uriTemplate: '/internal/download/{fileId}',
+            requirements: ['fileId' => '\\d+'],
+            processor: UploadRequestProcessor::class
+        )
+    ]
+)]
+class UploadRequest
+{
+    private int $fileId;
+
+    private string $content;
+
+    /**
+     * @return int
+     */
+    public function getFileId() : int
+    {
+        return $this->fileId;
+    }
+    /**
+     * @param int $fileId
+     */
+    public function setFileId(int $fileId) : void
+    {
+        $this->fileId = $fileId;
+    }
+
+    public function getContent(): string
+    {
+        return $this->content;
+    }
+
+    public function setContent(string $content): void
+    {
+        $this->content = $content;
+    }
+}

+ 1 - 1
src/Service/Export/BaseExporter.php

@@ -102,7 +102,7 @@ abstract class BaseExporter
         }
 
         // TODO: passer par le FileManager plutôt?
-        return $this->localStorage->writeFile($file, $content, $requester);
+        return $this->localStorage->write($file, $content, $requester);
     }
 
     /**

+ 15 - 0
src/Service/File/FileManager.php

@@ -7,6 +7,7 @@ use ApiPlatform\Api\IriConverterInterface;
 use ApiPlatform\Api\UrlGeneratorInterface;
 use ApiPlatform\Metadata\Get;
 use App\ApiResources\Core\File\DownloadRequest;
+use App\Entity\Access\Access;
 use App\Entity\Core\File;
 use App\Enum\Core\FileHostEnum;
 use App\Service\File\Exception\FileNotFoundException;
@@ -60,6 +61,20 @@ class FileManager
         return $storage->read($file);
     }
 
+    /**
+     * Write the $content into the file storage and update the given File object's size, slug, status (READY)...
+     *
+     * @param File $file
+     * @param string $content
+     * @param Access $author
+     * @return File
+     * @throws FileNotFoundException
+     */
+    public function write(File $file, string $content, Access $author): File {
+        $storage = $this->getStorageFor($file);
+        return $storage->write($file, $content, $author);
+    }
+
 
     /**
      * Get the IRI to download this file (eg: /api/download/1)

+ 9 - 0
src/Service/File/Storage/ApiLegacyStorage.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Service\File\Storage;
 
+use App\Entity\Access\Access;
 use App\Entity\Core\File;
 use App\Service\ApiLegacy\ApiLegacyRequestService;
 use App\Service\Utils\UrlBuilder;
@@ -20,6 +21,10 @@ class ApiLegacyStorage implements FileStorageInterface
     public function __construct(private ApiLegacyRequestService $apiLegacyRequestService)
     {}
 
+    public function exists(File $file, string $content, Access $author): File {
+        throw new \RuntimeException('not implemented error');
+    }
+
     /**
      * Reads the given file and returns its content as a string
      *
@@ -31,4 +36,8 @@ class ApiLegacyStorage implements FileStorageInterface
         $url = '_internal/secure/files/' . $file->getId();
         return $this->apiLegacyRequestService->getContent($url);
     }
+
+    public function write(File $file, string $content, Access $author): File {
+        throw new \RuntimeException('not implemented error');
+    }
 }

+ 6 - 1
src/Service/File/Storage/FileStorageInterface.php

@@ -3,11 +3,16 @@ declare(strict_types=1);
 
 namespace App\Service\File\Storage;
 
+use App\Entity\Access\Access;
 use App\Entity\Core\File;
 
 interface FileStorageInterface
 {
+    public function exists(File $file): bool;
+
     public function read(File $file): string;
 
-    // TODO : complete with 'exists', 'write', and 'delete'
+    public function write(File $file, string $content, Access $author): File;
+
+    // TODO : complete with 'delete'
 }

+ 2 - 2
src/Service/File/Storage/LocalStorage.php

@@ -136,7 +136,7 @@ class LocalStorage implements FileStorageInterface
      * @param Access $author The access responsible for the creation / update of the file
      * @return File
      */
-    public function writeFile(File $file, string $content, Access $author): File
+    public function write(File $file, string $content, Access $author): File
     {
         if (empty($file->getName())) {
             throw new RuntimeException('File has no filename');
@@ -223,7 +223,7 @@ class LocalStorage implements FileStorageInterface
             false
         );
 
-        return $this->writeFile($file, $content, $author);
+        return $this->write($file, $content, $author);
     }
 
     /**

+ 59 - 0
src/State/Processor/Core/UploadRequestProcessor.php

@@ -0,0 +1,59 @@
+<?php
+declare(strict_types=1);
+
+namespace App\State\Processor\Core;
+
+use ApiPlatform\Metadata\Delete;
+use ApiPlatform\Metadata\GetCollection;
+use ApiPlatform\Metadata\Operation;
+use ApiPlatform\State\ProcessorInterface;
+use ApiPlatform\State\ProviderInterface;
+use App\ApiResources\Core\File\DownloadRequest;
+use App\Entity\Access\Access;
+use App\Enum\Core\FileStatusEnum;
+use App\Repository\Core\FileRepository;
+use App\Service\File\Exception\FileNotFoundException;
+use App\Service\File\FileManager;
+use RuntimeException;
+use Symfony\Component\HttpFoundation\HeaderUtils;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * Custom provider pour le téléchargement des fichiers du LocalStorage
+ */
+final class UploadRequestProcessor implements ProcessorInterface
+{
+    public function __construct(
+        private readonly FileRepository $fileRepository,
+        private readonly FileManager    $fileManager,
+    ) {}
+
+    /**
+     * @param Operation $operation
+     * @param array<mixed> $uriVariables
+     * @param array<mixed> $context
+     * @return Response|RedirectResponse
+     * @throws FileNotFoundException
+     */
+    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): Response
+    {
+        if($operation instanceof Delete){
+            throw new RuntimeException('not supported', 500);
+        }
+
+        $fileId = $uriVariables['fileId'];
+        $file = $this->fileRepository->find($fileId);
+
+        if (empty($file)) {
+            throw new RuntimeException("File " . $fileId . " does not exist; abort.");
+        }
+
+        $content = '';
+
+        /** @var Access $access */
+        $author = $this->security->getUser();
+
+        $this->fileManager->write($file, $content, $author);
+    }
+}

+ 4 - 4
tests/Unit/Service/Export/BaseExporterTest.php

@@ -106,7 +106,7 @@ class BaseExporterTest extends TestCase
         $file = $this->getMockBuilder(File::class)->disableOriginalConstructor()->getMock();
         $this->fileRepository->method('find')->with(456, null, null)->willReturn($file);
 
-        $this->localStorage->expects(self::once())->method('writeFile')->with($file, $data, $access);
+        $this->localStorage->expects(self::once())->method('write')->with($file, $data, $access);
 
         $exporter->export($exportRequest);
     }
@@ -138,7 +138,7 @@ class BaseExporterTest extends TestCase
         $file = $this->getMockBuilder(File::class)->disableOriginalConstructor()->getMock();
         $exporter->expects(self::once())->method('prepareFile')->willReturn($file);
 
-        $this->localStorage->expects(self::once())->method('writeFile')->with($file, $data, $access);
+        $this->localStorage->expects(self::once())->method('write')->with($file, $data, $access);
 
         $exporter->export($exportRequest);
     }
@@ -155,7 +155,7 @@ class BaseExporterTest extends TestCase
 
         $this->accessRepository->method('find')->with(123, null, null)->willReturn(null);
 
-        $this->localStorage->expects(self::never())->method('writeFile');
+        $this->localStorage->expects(self::never())->method('write');
 
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Unable to determine the user; abort.');
@@ -186,7 +186,7 @@ class BaseExporterTest extends TestCase
         $access->method('getOrganization')->willReturn(null);
         $this->accessRepository->method('find')->with(123, null, null)->willReturn($access);
 
-        $this->localStorage->expects(self::never())->method('writeFile');
+        $this->localStorage->expects(self::never())->method('write');
 
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Unable to determine the organization of the curent user; abort.');

+ 11 - 11
tests/Unit/Service/File/Storage/LocalStorageTest.php

@@ -229,7 +229,7 @@ class LocalStorageTest extends TestCase
     }
 
     /**
-     * @see LocalStorage::writeFile()
+     * @see LocalStorage::write()
      */
     public function testWriteFileNewFile(): void {
         $fileStorage = $this->getMockBuilder(TestableLocalStorage::class)
@@ -277,13 +277,13 @@ class LocalStorageTest extends TestCase
 
         $this->entityManager->expects(self::once())->method('flush');
 
-        $returned = $fileStorage->writeFile($file, $content, $author);
+        $returned = $fileStorage->write($file, $content, $author);
 
         $this->assertEquals($file, $returned);
     }
 
     /**
-     * @see LocalStorage::writeFile()
+     * @see LocalStorage::write()
      */
     public function testWriteFileExistingFile(): void {
         $fileStorage = $this->getMockBuilder(TestableLocalStorage::class)
@@ -329,13 +329,13 @@ class LocalStorageTest extends TestCase
 
         $this->entityManager->expects(self::once())->method('flush');
 
-        $returned = $fileStorage->writeFile($file, $content, $author);
+        $returned = $fileStorage->write($file, $content, $author);
 
         $this->assertEquals($file, $returned);
     }
 
     /**
-     * @see LocalStorage::writeFile()
+     * @see LocalStorage::write()
      */
     public function testWriteFileExistingButMissingFile(): void
     {
@@ -365,11 +365,11 @@ class LocalStorageTest extends TestCase
         $this->expectException(RuntimeException::class);
         $this->expectDeprecationMessage('The file `' . $key . '` does not exist in the file storage');
 
-        $fileStorage->writeFile($file, '12346', $author);
+        $fileStorage->write($file, '12346', $author);
     }
 
     /**
-     * @see LocalStorage::writeFile()
+     * @see LocalStorage::write()
      */
     public function testWriteFileWithAccessOwner(): void {
         $fileStorage = $this->getMockBuilder(TestableLocalStorage::class)
@@ -407,11 +407,11 @@ class LocalStorageTest extends TestCase
         $content = '1';
         $this->filesystem->method('write')->willReturn(1);
 
-        $fileStorage->writeFile($file, $content, $author);
+        $fileStorage->write($file, $content, $author);
     }
 
     /**
-     * @see LocalStorage::writeFile()
+     * @see LocalStorage::write()
      */
     public function testWriteFileWithNoName(): void
     {
@@ -428,7 +428,7 @@ class LocalStorageTest extends TestCase
         $this->expectException(RuntimeException::class);
         $this->expectExceptionMessage('File has no filename');
 
-        $fileStorage->writeFile($file, '...', $author);
+        $fileStorage->write($file, '...', $author);
     }
 
     /**
@@ -452,7 +452,7 @@ class LocalStorageTest extends TestCase
 
         $fileStorage
             ->expects(self::once())
-            ->method('writeFile')
+            ->method('write')
             ->with($file, '...', $author)
             ->willReturn($file);