diff --git a/.editorconfig b/.editorconfig index d769b46a4..fe115d4c0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ charset = utf-8 end_of_line = LF insert_final_newline = true trim_trailing_whitespace = true +indent_size = 4 [*.{php,html,twig}] indent_style = space diff --git a/composer.json b/composer.json index 747747290..0d134cbf8 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "league/csv": "^9.7.1", "nyholm/psr7": "^1.4", "phpoffice/phpspreadsheet": "^1.16", + "ramsey/uuid-doctrine": "^1.7", "sensio/framework-extra-bundle": "^5.5", "symfony/asset": "4.*", "symfony/browser-kit": "^5.2", @@ -29,6 +30,7 @@ "symfony/expression-language": "4.*", "symfony/form": "4.*", "symfony/intl": "4.*", + "symfony/mime": "^4 || ^5", "symfony/monolog-bundle": "^3.5", "symfony/security-bundle": "4.*", "symfony/serializer": "^5.2", diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php index 9c88e502d..7ba21b5da 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -7,7 +7,9 @@ namespace Chill\DocStoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface; use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists; +use ChampsLibres\WopiLib\Contract\Entity\Document; use DateTimeInterface; +use Ramsey\Uuid\Uuid; use Symfony\Component\Serializer\Annotation as Serializer; /** @@ -19,7 +21,7 @@ use Symfony\Component\Serializer\Annotation as Serializer; * message="The file is not stored properly" * ) */ -class StoredObject implements AsyncFileInterface +class StoredObject implements AsyncFileInterface, Document { /** * @ORM\Id() @@ -47,6 +49,11 @@ class StoredObject implements AsyncFileInterface */ private array $iv = []; + /** + * @ORM\Column(type="uuid", unique=true) + */ + private Uuid $uuid; + /** * @ORM\Column(type="datetime", name="creation_date") * @Serializer\Groups({"read"}) @@ -68,6 +75,7 @@ class StoredObject implements AsyncFileInterface public function __construct() { $this->creationDate = new \DateTime(); + $this->uuid = Uuid::uuid4(); } public function getId() @@ -155,5 +163,13 @@ class StoredObject implements AsyncFileInterface return $this; } + public function getUuid(): Uuid + { + return $this->uuid; + } + public function getWopiDocId(): string + { + return (string) $this->uuid; + } } diff --git a/src/Bundle/ChillDocStoreBundle/composer.json b/src/Bundle/ChillDocStoreBundle/composer.json index 384f6c093..c011ce29b 100644 --- a/src/Bundle/ChillDocStoreBundle/composer.json +++ b/src/Bundle/ChillDocStoreBundle/composer.json @@ -3,9 +3,12 @@ "description": "A Chill bundle to store documents", "type": "symfony-bundle", "autoload": { - "psr-4": { "Chill\\DocStoreBundle\\" : "" } + "psr-4": { + "Chill\\DocStoreBundle\\": "" + } }, "require": { + "symfony/mime": "^4 || ^5" }, "license": "AGPL-3.0" } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php new file mode 100644 index 000000000..756faf654 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php @@ -0,0 +1,30 @@ +addSql('ALTER TABLE chill_doc.stored_object ADD uuid UUID NOT NULL'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_49604E36D17F50A6 ON chill_doc.stored_object (uuid)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_49604E36D17F50A6'); + $this->addSql('ALTER TABLE chill_doc.stored_object DROP uuid'); + } +} diff --git a/src/Bundle/ChillWopiBundle/composer.json b/src/Bundle/ChillWopiBundle/composer.json index 7f7e6a4ed..41737c8b1 100644 --- a/src/Bundle/ChillWopiBundle/composer.json +++ b/src/Bundle/ChillWopiBundle/composer.json @@ -19,7 +19,7 @@ "php": ">= 7.4", "champs-libres/wopi-bundle": "dev-master", "nyholm/psr7": "^1.4", - "php-opencloud/openstack": "^3.2.1" + "symfony/mime": "^4 || ^5" }, "autoload": { "psr-4": { diff --git a/src/Bundle/ChillWopiBundle/src/Controller/Test.php b/src/Bundle/ChillWopiBundle/src/Controller/Test.php index 202af20aa..283328f21 100644 --- a/src/Bundle/ChillWopiBundle/src/Controller/Test.php +++ b/src/Bundle/ChillWopiBundle/src/Controller/Test.php @@ -9,9 +9,10 @@ declare(strict_types=1); namespace Chill\WopiBundle\Controller; -use ChampsLibres\WopiLib\Configuration\WopiConfigurationInterface; -use ChampsLibres\WopiLib\Discovery\WopiDiscoveryInterface; -use Chill\DocStoreBundle\Repository\StoredObjectRepository; +use ChampsLibres\WopiLib\Contract\Service\Configuration\ConfigurationInterface; +use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface; +use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; +use Chill\DocStoreBundle\Entity\StoredObject; use Chill\WopiBundle\Service\Controller\ResponderInterface; use Exception; use loophp\psr17\Psr17Interface; @@ -23,11 +24,11 @@ use Symfony\Component\Security\Core\Security; final class Test { - private StoredObjectRepository $storedObjectRepository; + private DiscoveryInterface $wopiDiscovery; - private WopiDiscoveryInterface $wopiDiscovery; + private DocumentManagerInterface $documentManager; - private WopiConfigurationInterface $wopiConfiguration; + private ConfigurationInterface $wopiConfiguration; private ResponderInterface $responder; @@ -38,15 +39,15 @@ final class Test private RouterInterface $router; public function __construct( - StoredObjectRepository $storedObjectRepository, - WopiConfigurationInterface $wopiConfiguration, - WopiDiscoveryInterface $wopiDiscovery, + ConfigurationInterface $wopiConfiguration, + DiscoveryInterface $wopiDiscovery, + DocumentManagerInterface $documentManager, ResponderInterface $responder, Security $security, Psr17Interface $psr17, RouterInterface $router ) { - $this->storedObjectRepository = $storedObjectRepository; + $this->documentManager = $documentManager; $this->wopiConfiguration = $wopiConfiguration; $this->wopiDiscovery = $wopiDiscovery; $this->responder = $responder; @@ -58,11 +59,11 @@ final class Test public function __invoke(string $fileId): Response { $configuration = $this->wopiConfiguration->jsonSerialize(); - - $storedObject = $this->storedObjectRepository->findOneBy(['filename' => $fileId]); + /** @var StoredObject $storedObject */ + $storedObject = $this->documentManager->findByDocumentId($fileId); if (null === $storedObject) { - throw new NotFoundHttpException(sprintf('Unable to find object named %s', $fileId)); + throw new NotFoundHttpException(sprintf('Unable to find object %s', $fileId)); } if ([] === $discoverExtension = $this->wopiDiscovery->discoverMimeType($storedObject->getType())) { @@ -83,7 +84,7 @@ final class Test ->generate( 'checkFileInfo', [ - 'fileId' => $storedObject->getFilename(), + 'fileId' => $this->documentManager->getDocumentId($storedObject), ], UrlGeneratorInterface::ABSOLUTE_URL ), diff --git a/src/Bundle/ChillWopiBundle/src/Resources/config/services.php b/src/Bundle/ChillWopiBundle/src/Resources/config/services.php index 455e658e2..4925404b3 100644 --- a/src/Bundle/ChillWopiBundle/src/Resources/config/services.php +++ b/src/Bundle/ChillWopiBundle/src/Resources/config/services.php @@ -10,8 +10,10 @@ declare(strict_types=1); namespace Symfony\Component\DependencyInjection\Loader\Configurator; use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface; -use ChampsLibres\WopiLib\Service\Contract\WopiInterface; use Chill\WopiBundle\Service\Wopi\ChillWopi; +use ChampsLibres\WopiBundle\Service\Wopi as CLWopi; +use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; +use Chill\WopiBundle\Service\Wopi\ChillDocumentManager; return static function (ContainerConfigurator $container) { $services = $container @@ -30,8 +32,14 @@ return static function (ContainerConfigurator $container) { ->tag('controller.service_arguments'); $services - ->alias(WopiInterface::class, ChillWopi::class); + ->set(ChillWopi::class) + ->decorate(CLWopi::class) + ->arg('$wopi', service('.inner')); + $services + ->alias(DocumentManagerInterface::class, ChillDocumentManager::class); + + // TODO: Move this into the async bundle (low priority) $services ->alias(TempUrlGeneratorInterface::class, 'async_uploader.temp_url_generator'); }; diff --git a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentManager.php b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentManager.php new file mode 100644 index 000000000..bfa3ee8b0 --- /dev/null +++ b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentManager.php @@ -0,0 +1,243 @@ +entityManager = $entityManager; + $this->psr17 = $psr17; + $this->storedObjectRepository = $storedObjectRepository; + $this->documentLockManager = $documentLockManager; + $this->tempUrlGenerator = $tempUrlGenerator; + $this->httpClient = $httpClient; + $this->request = $httpMessageFactory->createRequest($requestStack->getCurrentRequest()); + } + + public function create(array $data): Document + { + /** @var StoredObject $document */ + $document = (new ObjectNormalizer())->denormalize([], StoredObject::class); + + // Mime types / extension handling. + $mimeTypes = new MimeTypes(); + $mimeTypes->getMimeTypes($data['extension']); + $document->setType(reset($mimeTypes)); + + $document->setFilename($data['name']); + + $this->entityManager->persist($document); + $this->entityManager->flush($document); + + // TODO : Ask proper mapping. + // Available: basename, name, extension, content, size + $this->setContent($document, $data['content']); + + return $document; + } + + public function deleteLock(Document $document): void { + $this->documentLockManager->deleteLock($document, $this->request); + } + + /** + * @param string $documentFilename without extension ! + */ + public function findByDocumentFilename(string $documentFilename): ?Document { + return $this->storedObjectRepository->findOneBy( + [ + 'filename' => $documentFilename, + ] + ); + } + + public function findByDocumentId(string $documentId): ?Document { + return $this->storedObjectRepository->findOneBy( + [ + 'uuid' => $documentId, + ] + ); + } + + /** + * @param StoredObject $document + */ + public function getCreationDate(Document $document): DateTimeInterface + { + return $document->getCreationDate(); + } + + /** + * @param StoredObject $document + */ + public function getLastModifiedDate(Document $document): DateTimeInterface + { + // TODO: Add column 'LastModifiedDate' in StoredObject entity + return $document->getCreationDate(); + } + + public function getLock(Document $document): string { + return $this->documentLockManager->getLock($document, $this->request); + } + + public function getVersion(Document $document): string { + // TODO ? + return '0'; + } + + public function hasLock(Document $document): bool { + return $this->documentLockManager->hasLock($document, $this->request); + } + + public function lock(Document $document, string $lock): void { + $this->documentLockManager->setLock($document, $lock, $this->request); + } + + public function remove(Document $document): void { + $entityIsDeleted = false; + + try { + $this->entityManager->remove($document); + $entityIsDeleted = true; + } catch (Throwable $e) { + $entityIsDeleted = false; + } + + if ($entityIsDeleted === true) { + $this->deleteContent($document); + } + } + + public function write(Document $document, array $properties = []): void + { + $this->setContent($document, $properties['content']); + } + + /** + * @param StoredObject $document + * + * @return string The document filename with its extension. + */ + public function getBasename(Document $document): string { + $exts = (new MimeTypes())->getExtensions($document->getType()); + + if ([] === $exts) { + throw new Error('Unknown mimetype for stored document.'); + } + + return sprintf('%s.%s', $document->getFilename(), reset($exts)); + } + + /** + * @param StoredObject $document + */ + public function getDocumentId(Document $document): string { + return (string) $document->getUuid(); + } + + public function getSha256(Document $document): string { + return base64_encode(hash('sha256', $this->getContent($document))); + } + + public function getSize(Document $document): int { + return strlen(stream_get_contents($this->read($document))); + } + + public function read(Document $document): StreamInterface { + return $this + ->psr17 + ->createStream($this->getContent($document)); + } + + private function deleteContent(StoredObject $storedObject): string + { + /** @var StdClass $object */ + $object = $this->tempUrlGenerator->generate('DELETE', $storedObject->getFilename()); + + $response = $this->httpClient->request('DELETE', $object->url); + + if (200 !== $response->getStatusCode()) + { + throw new Error('Unable to delete stored object.'); + } + } + + private function getContent(StoredObject $storedObject): string + { + /** @var StdClass $object */ + $object = $this->tempUrlGenerator->generate('GET', $storedObject->getFilename()); + + $response = $this->httpClient->request('GET', $object->url); + + if (200 !== $response->getStatusCode()) + { + throw new Error('Unable to retrieve stored object.'); + } + + return $response->getContent(); + } + + private function setContent(StoredObject $storedObject, string $content): void + { + // TODO: Add strict typing in champs-libres/async-uploader-bundle + /** @var StdClass $object */ + $object = $this->tempUrlGenerator->generate('PUT', $storedObject->getFilename()); + + $response = $this->httpClient->request('PUT', $object->url, ['body' => $content]); + + if (200 !== $response->getStatusCode()) + { + throw new Error('Unable to save stored object.'); + } + } + +} diff --git a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php index fc4e526a1..7061c5735 100644 --- a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php +++ b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php @@ -9,46 +9,28 @@ declare(strict_types=1); namespace Chill\WopiBundle\Service\Wopi; -use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface; -use ChampsLibres\WopiLib\Discovery\WopiDiscoveryInterface; -use ChampsLibres\WopiLib\Service\Contract\WopiInterface; -use Chill\DocStoreBundle\Repository\StoredObjectRepository; -use Exception; +use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; +use ChampsLibres\WopiLib\Contract\Service\WopiInterface; use loophp\psr17\Psr17Interface; -use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; -use Symfony\Component\Security\Core\User\UserProviderInterface; final class ChillWopi implements WopiInterface { + private DocumentManagerInterface $documentManager; + private Psr17Interface $psr17; - private WopiDiscoveryInterface $wopiDiscovery; - - private StoredObjectRepository $storedObjectRepository; - - private ClientInterface $httpClient; - - private TempUrlGeneratorInterface $tempUrlGenerator; - - private UserProviderInterface $userProvider; + private WopiInterface $wopi; public function __construct( + DocumentManagerInterface $documentManager, Psr17Interface $psr17, - WopiDiscoveryInterface $wopiDiscovery, - StoredObjectRepository $storedObjectRepository, - ClientInterface $httpClient, - TempUrlGeneratorInterface $tempUrlGenerator, - UserProviderInterface $userProvider + WopiInterface $wopi ) { + $this->documentManager = $documentManager; $this->psr17 = $psr17; - $this->wopiDiscovery = $wopiDiscovery; - $this->storedObjectRepository = $storedObjectRepository; - $this->httpClient = $httpClient; - $this->tempUrlGenerator = $tempUrlGenerator; - $this->userProvider = $userProvider; + $this->wopi = $wopi; } public function checkFileInfo( @@ -56,59 +38,31 @@ final class ChillWopi implements WopiInterface ?string $accessToken, RequestInterface $request ): ResponseInterface { - try { - $user = $this->userProvider->loadUserByUsername($accessToken); - } catch (UsernameNotFoundException $e) { - return $this - ->psr17 - ->createResponse(401); - } + $response = $this->wopi->checkFileInfo($fileId, $accessToken, $request); + $document = $this->documentManager->findByDocumentId($fileId); - $storedObject = $this->storedObjectRepository->findOneBy(['filename' => $fileId]); + $body = json_decode((string) $response->getBody(), true); - if (null === $storedObject) { - throw new Exception(sprintf('Unable to find object named %s', $fileId)); - } - - $mimeType = $storedObject->getType(); - - if ([] === $this->wopiDiscovery->discoverMimeType($mimeType)) { - throw new Exception(sprintf('Unable to find mime type %s', $mimeType)); - } - - return $this - ->psr17 - ->createResponse() - ->withHeader('Content-Type', 'application/json') - ->withBody($this->psr17->createStream((string) json_encode( - [ - 'BaseFileName' => $storedObject->getFilename(), - 'OwnerId' => uniqid(), - 'Size' => 0, - 'UserId' => uniqid(), -// 'Version' => 'v' . uniqid(), - 'ReadOnly' => false, - 'UserCanWrite' => true, - 'UserCanNotWriteRelative' => true, - 'SupportsLocks' => false, - 'UserFriendlyName' => sprintf('User %s', $user->getUsername()), - 'UserExtraInfo' => [], - 'LastModifiedTime' => date('Y-m-d\TH:i:s.u\Z', $storedObject->getCreationDate()->getTimestamp()), - 'CloseButtonClosesWindow' => true, - 'EnableInsertRemoteImage' => true, - 'EnableShare' => false, - 'SupportsUpdate' => true, - 'SupportsRename' => false, - 'DisablePrint' => false, - 'DisableExport' => false, - 'DisableCopy' => false, - ] - ))); + return $response + ->withBody( + $this + ->psr17 + ->createStream( + (string) json_encode( + $body + + [ + 'Version' => sprintf('v%s', $this->documentManager->getVersion($document)), + // TODO: Add column 'LastModifiedDate' in StoredObject entity + 'LastModifiedTime' => $this->documentManager->getLastModifiedDate($document)->format('Y-m-d\TH:i:s.uP'), + ] + ) + ) + ); } public function deleteFile(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->deleteFile($fileId, $accessToken, $request); } public function enumerateAncestors( @@ -116,57 +70,17 @@ final class ChillWopi implements WopiInterface ?string $accessToken, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->enumerateAncestors($fileId, $accessToken, $request); } public function getFile(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface { - try { - $user = $this->userProvider->loadUserByUsername($accessToken); - } catch (UsernameNotFoundException $e) { - return $this - ->psr17 - ->createResponse(401); - } - - $storedObject = $this->storedObjectRepository->findOneBy(['filename' => $fileId]); - - if (null === $storedObject) { - return $this - ->psr17 - ->createResponse(404); - } - - // TODO: Add strict typing in champs-libres/async-uploader-bundle - /** @var StdClass $object */ - $object = $this->tempUrlGenerator->generate('GET', $storedObject->getFilename()); - - $response = $this->httpClient->sendRequest($this->psr17->createRequest('GET', $object->url)); - - if (200 !== $response->getStatusCode()) - { - return $this - ->psr17 - ->createResponse(500); - } - - return $this - ->psr17 - ->createResponse() - ->withHeader( - 'Content-Type', - 'application/octet-stream', - ) - ->withHeader( - 'Content-Disposition', - sprintf('attachment; filename=%s', $storedObject->getFilename()) - ) - ->withBody($response->getBody()); + return $this->wopi->getFile($fileId, $accessToken, $request); } public function getLock(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->getLock($fileId, $accessToken, $request); } public function getShareUrl( @@ -174,7 +88,7 @@ final class ChillWopi implements WopiInterface ?string $accessToken, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->getShareUrl($fileId, $accessToken, $request); } public function lock( @@ -183,7 +97,7 @@ final class ChillWopi implements WopiInterface string $xWopiLock, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->lock($fileId, $accessToken, $xWopiLock, $request); } public function putFile( @@ -193,49 +107,17 @@ final class ChillWopi implements WopiInterface string $xWopiEditors, RequestInterface $request ): ResponseInterface { - try { - $user = $this->userProvider->loadUserByUsername($accessToken); - } catch (UsernameNotFoundException $e) { - return $this - ->psr17 - ->createResponse(401); - } - - $storedObject = $this->storedObjectRepository->findOneBy(['filename' => $fileId]); - - if (null === $storedObject) { - throw new Exception(sprintf('Unable to find object named %s', $fileId)); - } - - // TODO: Add strict typing in champs-libres/async-uploader-bundle - /** @var StdClass $object */ - $object = $this->tempUrlGenerator->generate('PUT', $storedObject->getFilename()); - - $response = $this->httpClient->sendRequest($this->psr17->createRequest('PUT', $object->url)->withBody($request->getBody())); - - if (201 !== $response->getStatusCode()) - { - return $this - ->psr17 - ->createResponse(500); - } - - return $this - ->psr17 - ->createResponse() - ->withHeader('Content-Type', 'application/json') - ->withAddedHeader('X-WOPI-Lock', $xWopiLock) - ->withBody($this->psr17->createStream((string) json_encode([]))); + return $this->wopi->putFile($fileId, $accessToken, $xWopiLock, $xWopiEditors, $request); } public function putRelativeFile(string $fileId, string $accessToken, ?string $suggestedTarget, ?string $relativeTarget, bool $overwriteRelativeTarget, int $size, RequestInterface $request): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->putRelativeFile($fileId, $accessToken, $suggestedTarget, $relativeTarget, $overwriteRelativeTarget, $size, $request); } public function putUserInfo(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->putUserInfo($fileId, $accessToken, $request); } public function refreshLock( @@ -244,7 +126,7 @@ final class ChillWopi implements WopiInterface string $xWopiLock, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->refreshLock($fileId, $accessToken, $xWopiLock, $request); } public function renameFile( @@ -254,7 +136,7 @@ final class ChillWopi implements WopiInterface string $xWopiRequestedName, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->renameFile($fileId, $accessToken, $xWopiLock, $xWopiRequestedName, $request); } public function unlock( @@ -263,7 +145,7 @@ final class ChillWopi implements WopiInterface string $xWopiLock, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); + return $this->wopi->unlock($fileId, $accessToken, $xWopiLock, $request); } public function unlockAndRelock( @@ -273,33 +155,6 @@ final class ChillWopi implements WopiInterface string $xWopiOldLock, RequestInterface $request ): ResponseInterface { - return $this->getDebugResponse(__FUNCTION__, $request); - } - - private function getDebugResponse(string $method, RequestInterface $request): ResponseInterface - { - $params = []; - parse_str($request->getUri()->getQuery(), $params); - - $data = (string) json_encode(array_merge( - ['method' => $method], - $params, - $request->getHeaders() - )); - - return $this - ->psr17 - ->createResponse() - ->withHeader('content', 'application/json') - ->withBody($this->psr17->createStream($data)); - } - - private function getLockFilepath(string $fileId): string - { - return sprintf( - '%s/%s.lock', - $this->filesRepository, - $fileId - ); + return $this->wopi->unlockAndRelock($fileId, $accessToken, $xWopiLock, $xWopiOldLock, $request); } }