mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-04-14 09:59:33 +00:00
Add _editor and lock to StoredObjecNormalizer. Refactor StoredObjectNormalizerTest to use prophecy and add tests for lock and editor states
- Replaced PHPUnit mocks with prophecy for improved flexibility in `StoredObjectNormalizerTest`. - Added test cases to cover lock handling and editor state evaluation for WebDAV and WOPI methods. - Updated `StoredObjectNormalizer` to include lock normalization and editor state computation logic. - Extended TypeScript types to reflect lock and editor states in the front-end model.
This commit is contained in:
@@ -3,6 +3,16 @@ import { SignedUrlGet } from "ChillDocStoreAssets/vuejs/StoredObjectButton/helpe
|
||||
|
||||
export type StoredObjectStatus = "empty" | "ready" | "failure" | "pending";
|
||||
|
||||
export type StoredObjectLockMethodEnum = 'webdav' | 'wopi';
|
||||
|
||||
export interface StoredObjectLock {
|
||||
uuid: string;
|
||||
method: StoredObjectLockMethodEnum;
|
||||
createdAt: DateTime;
|
||||
expiresAt: DateTime;
|
||||
users: User[];
|
||||
}
|
||||
|
||||
export interface StoredObject {
|
||||
id: number;
|
||||
title: string | null;
|
||||
@@ -31,6 +41,11 @@ export interface StoredObject {
|
||||
};
|
||||
downloadLink?: SignedUrlGet;
|
||||
};
|
||||
lock: StoredObjectLock|null;
|
||||
_editor?: {
|
||||
webdav: boolean;
|
||||
wopi: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface StoredObjectVersion {
|
||||
|
||||
@@ -13,8 +13,11 @@ namespace Chill\DocStoreBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface;
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Entity\StoredObjectLockMethodEnum;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\DocStoreBundle\Security\Guard\JWTDavTokenProviderInterface;
|
||||
use Chill\DocStoreBundle\Service\Lock\StoredObjectEditorDecisionManagerInterface;
|
||||
use Chill\DocStoreBundle\Service\Lock\StoredObjectLockManager;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
@@ -42,6 +45,8 @@ final class StoredObjectNormalizer implements NormalizerInterface, NormalizerAwa
|
||||
private readonly UrlGeneratorInterface $urlGenerator,
|
||||
private readonly Security $security,
|
||||
private readonly TempUrlGeneratorInterface $tempUrlGenerator,
|
||||
private readonly StoredObjectEditorDecisionManagerInterface $storedObjectEditorDecisionManager,
|
||||
private readonly StoredObjectLockManager $storedObjectLockManager,
|
||||
) {}
|
||||
|
||||
public function normalize($object, ?string $format = null, array $context = [])
|
||||
@@ -58,6 +63,7 @@ final class StoredObjectNormalizer implements NormalizerInterface, NormalizerAwa
|
||||
'createdBy' => $this->normalizer->normalize($object->getCreatedBy(), $format, $context),
|
||||
'currentVersion' => $this->normalizer->normalize($object->getCurrentVersion(), $format, [...$context, [AbstractNormalizer::GROUPS => 'read']]),
|
||||
'totalVersions' => $object->getVersions()->count(),
|
||||
'lock' => $this->storedObjectLockManager->hasLock($object) ? $this->normalizer->normalize($this->storedObjectLockManager->getLock($object), $format, $context) : null,
|
||||
];
|
||||
|
||||
// deprecated property
|
||||
@@ -110,6 +116,11 @@ final class StoredObjectNormalizer implements NormalizerInterface, NormalizerAwa
|
||||
];
|
||||
}
|
||||
|
||||
$datas['_editor'] = [
|
||||
'webdav' => $canEdit && $this->storedObjectEditorDecisionManager->canEdit($object, StoredObjectLockMethodEnum::WEBDAV),
|
||||
'wopi' => $canEdit && $this->storedObjectEditorDecisionManager->canEdit($object, StoredObjectLockMethodEnum::WOPI),
|
||||
];
|
||||
|
||||
return $datas;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,15 @@ namespace Chill\DocStoreBundle\Tests\Serializer\Normalizer;
|
||||
use Chill\DocStoreBundle\AsyncUpload\SignedUrl;
|
||||
use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface;
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\DocStoreBundle\Entity\StoredObjectLock;
|
||||
use Chill\DocStoreBundle\Entity\StoredObjectLockMethodEnum;
|
||||
use Chill\DocStoreBundle\Security\Guard\JWTDavTokenProviderInterface;
|
||||
use Chill\DocStoreBundle\Serializer\Normalizer\StoredObjectNormalizer;
|
||||
use Chill\DocStoreBundle\Service\Lock\StoredObjectEditorDecisionManagerInterface;
|
||||
use Chill\DocStoreBundle\Service\Lock\StoredObjectLockManager;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
@@ -29,6 +34,8 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
*/
|
||||
class StoredObjectNormalizerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function testNormalize(): void
|
||||
{
|
||||
$storedObject = new StoredObject();
|
||||
@@ -37,45 +44,51 @@ class StoredObjectNormalizerTest extends TestCase
|
||||
$idProperty = $reflection->getProperty('id');
|
||||
$idProperty->setValue($storedObject, 1);
|
||||
|
||||
$jwtProvider = $this->createMock(JWTDavTokenProviderInterface::class);
|
||||
$jwtProvider->expects($this->once())->method('createToken')->withAnyParameters()->willReturn('token');
|
||||
$jwtProvider->expects($this->once())->method('getTokenExpiration')->with('token')->willReturn($d = new \DateTimeImmutable());
|
||||
$jwtProvider = $this->prophesize(JWTDavTokenProviderInterface::class);
|
||||
$jwtProvider->createToken(Argument::cetera())->willReturn('token');
|
||||
$jwtProvider->getTokenExpiration('token')->willReturn($d = new \DateTimeImmutable());
|
||||
|
||||
$urlGenerator = $this->createMock(UrlGeneratorInterface::class);
|
||||
$urlGenerator->expects($this->once())->method('generate')
|
||||
->with(
|
||||
'chill_docstore_dav_document_get',
|
||||
[
|
||||
'uuid' => $storedObject->getUuid(),
|
||||
'access_token' => 'token',
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL,
|
||||
)
|
||||
->willReturn($davLink = 'http://localhost/dav/token');
|
||||
$urlGenerator = $this->prophesize(UrlGeneratorInterface::class);
|
||||
$urlGenerator->generate(
|
||||
'chill_docstore_dav_document_get',
|
||||
[
|
||||
'uuid' => $storedObject->getUuid(),
|
||||
'access_token' => 'token',
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL,
|
||||
)->willReturn($davLink = 'http://localhost/dav/token');
|
||||
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->expects($this->exactly(2))->method('isGranted')
|
||||
->with(
|
||||
$this->logicalOr(StoredObjectRoleEnum::EDIT->value, StoredObjectRoleEnum::SEE->value),
|
||||
$storedObject
|
||||
)
|
||||
->willReturn(true);
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted(Argument::type('string'), $storedObject)->willReturn(true);
|
||||
|
||||
$globalNormalizer = $this->createMock(NormalizerInterface::class);
|
||||
$globalNormalizer->expects($this->exactly(3))->method('normalize')
|
||||
->withAnyParameters()
|
||||
->willReturnCallback(function (?object $object, string $format, array $context) {
|
||||
if (null === $object) {
|
||||
$globalNormalizer = $this->prophesize(NormalizerInterface::class);
|
||||
$globalNormalizer->normalize(Argument::cetera())
|
||||
->will(function ($args) {
|
||||
if (null === $args[0]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ['sub' => 'sub'];
|
||||
});
|
||||
|
||||
$tempUrlGenerator = $this->createMock(TempUrlGeneratorInterface::class);
|
||||
$tempUrlGenerator = $this->prophesize(TempUrlGeneratorInterface::class);
|
||||
|
||||
$normalizer = new StoredObjectNormalizer($jwtProvider, $urlGenerator, $security, $tempUrlGenerator);
|
||||
$normalizer->setNormalizer($globalNormalizer);
|
||||
$storedObjectEditorDecisionManager = $this->prophesize(StoredObjectEditorDecisionManagerInterface::class);
|
||||
$storedObjectEditorDecisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WEBDAV)->willReturn(true);
|
||||
$storedObjectEditorDecisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WOPI)->willReturn(true);
|
||||
|
||||
$storedObjectLockManager = $this->prophesize(StoredObjectLockManager::class);
|
||||
$storedObjectLockManager->hasLock($storedObject)->willReturn(false);
|
||||
|
||||
$normalizer = new StoredObjectNormalizer(
|
||||
$jwtProvider->reveal(),
|
||||
$urlGenerator->reveal(),
|
||||
$security->reveal(),
|
||||
$tempUrlGenerator->reveal(),
|
||||
$storedObjectEditorDecisionManager->reveal(),
|
||||
$storedObjectLockManager->reveal()
|
||||
);
|
||||
$normalizer->setNormalizer($globalNormalizer->reveal());
|
||||
|
||||
$actual = $normalizer->normalize($storedObject, 'json');
|
||||
|
||||
@@ -93,11 +106,67 @@ class StoredObjectNormalizerTest extends TestCase
|
||||
self::assertArrayHasKey('datas', $actual);
|
||||
self::assertArrayHasKey('createdAt', $actual);
|
||||
self::assertArrayHasKey('createdBy', $actual);
|
||||
self::assertArrayHasKey('lock', $actual);
|
||||
self::assertNull($actual['lock']);
|
||||
self::assertArrayHasKey('_permissions', $actual);
|
||||
self::assertEqualsCanonicalizing(['canEdit' => true, 'canSee' => true], $actual['_permissions']);
|
||||
self::assertArrayHaskey('_links', $actual);
|
||||
self::assertArrayHasKey('dav_link', $actual['_links']);
|
||||
self::assertEqualsCanonicalizing(['href' => $davLink, 'expiration' => $d->getTimestamp()], $actual['_links']['dav_link']);
|
||||
self::assertArrayHasKey('_editor', $actual);
|
||||
self::assertArrayHasKey('webdav', $actual['_editor']);
|
||||
self::assertArrayHasKey('wopi', $actual['_editor']);
|
||||
self::assertTrue($actual['_editor']['webdav']);
|
||||
self::assertTrue($actual['_editor']['wopi']);
|
||||
}
|
||||
|
||||
public function testNormalizeWithLock(): void
|
||||
{
|
||||
$storedObject = new StoredObject();
|
||||
$storedObject->setTitle('test');
|
||||
$reflection = new \ReflectionClass(StoredObject::class);
|
||||
$idProperty = $reflection->getProperty('id');
|
||||
$idProperty->setValue($storedObject, 1);
|
||||
|
||||
$jwtProvider = $this->prophesize(JWTDavTokenProviderInterface::class);
|
||||
$jwtProvider->createToken(Argument::cetera())->willReturn('token');
|
||||
$jwtProvider->getTokenExpiration('token')->willReturn(new \DateTimeImmutable());
|
||||
$urlGenerator = $this->prophesize(UrlGeneratorInterface::class);
|
||||
$urlGenerator->generate(Argument::cetera())->willReturn('http://localhost');
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted(Argument::cetera())->willReturn(true);
|
||||
|
||||
$lock = $this->prophesize(StoredObjectLock::class);
|
||||
|
||||
$globalNormalizer = $this->prophesize(NormalizerInterface::class);
|
||||
$globalNormalizer->normalize(Argument::cetera())->willReturn(['sub' => 'sub']);
|
||||
|
||||
$tempUrlGenerator = $this->prophesize(TempUrlGeneratorInterface::class);
|
||||
|
||||
$storedObjectEditorDecisionManager = $this->prophesize(StoredObjectEditorDecisionManagerInterface::class);
|
||||
$storedObjectEditorDecisionManager->canEdit(Argument::cetera())->willReturn(false);
|
||||
|
||||
$storedObjectLockManager = $this->prophesize(StoredObjectLockManager::class);
|
||||
$storedObjectLockManager->hasLock($storedObject)->willReturn(true);
|
||||
$storedObjectLockManager->getLock($storedObject)->willReturn($lock->reveal());
|
||||
|
||||
$normalizer = new StoredObjectNormalizer(
|
||||
$jwtProvider->reveal(),
|
||||
$urlGenerator->reveal(),
|
||||
$security->reveal(),
|
||||
$tempUrlGenerator->reveal(),
|
||||
$storedObjectEditorDecisionManager->reveal(),
|
||||
$storedObjectLockManager->reveal()
|
||||
);
|
||||
$normalizer->setNormalizer($globalNormalizer->reveal());
|
||||
|
||||
$actual = $normalizer->normalize($storedObject, 'json');
|
||||
|
||||
self::assertArrayHasKey('lock', $actual);
|
||||
self::assertEquals(['sub' => 'sub'], $actual['lock']);
|
||||
self::assertArrayHasKey('_editor', $actual);
|
||||
self::assertFalse($actual['_editor']['webdav']);
|
||||
self::assertFalse($actual['_editor']['wopi']);
|
||||
}
|
||||
|
||||
public function testWithDownloadLinkOnly(): void
|
||||
@@ -109,32 +178,42 @@ class StoredObjectNormalizerTest extends TestCase
|
||||
$idProperty = $reflection->getProperty('id');
|
||||
$idProperty->setValue($storedObject, 1);
|
||||
|
||||
$jwtProvider = $this->createMock(JWTDavTokenProviderInterface::class);
|
||||
$jwtProvider->expects($this->never())->method('createToken')->withAnyParameters();
|
||||
$jwtProvider = $this->prophesize(JWTDavTokenProviderInterface::class);
|
||||
$jwtProvider->createToken(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$urlGenerator = $this->createMock(UrlGeneratorInterface::class);
|
||||
$urlGenerator->expects($this->never())->method('generate');
|
||||
$urlGenerator = $this->prophesize(UrlGeneratorInterface::class);
|
||||
$urlGenerator->generate(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->expects($this->never())->method('isGranted');
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$globalNormalizer = $this->createMock(NormalizerInterface::class);
|
||||
$globalNormalizer->expects($this->exactly(4))->method('normalize')
|
||||
->withAnyParameters()
|
||||
->willReturnCallback(function (?object $object, string $format, array $context) {
|
||||
if (null === $object) {
|
||||
$globalNormalizer = $this->prophesize(NormalizerInterface::class);
|
||||
$globalNormalizer->normalize(Argument::cetera())
|
||||
->will(function ($args) {
|
||||
if (null === $args[0]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ['sub' => 'sub'];
|
||||
});
|
||||
|
||||
$tempUrlGenerator = $this->createMock(TempUrlGeneratorInterface::class);
|
||||
$tempUrlGenerator->expects($this->once())->method('generate')->with('GET', $storedObject->getCurrentVersion()->getFilename(), $this->isType('int'))
|
||||
$tempUrlGenerator = $this->prophesize(TempUrlGeneratorInterface::class);
|
||||
$tempUrlGenerator->generate('GET', $storedObject->getCurrentVersion()->getFilename(), Argument::type('int'))
|
||||
->willReturn(new SignedUrl('GET', 'https://some-link/test', new \DateTimeImmutable('300 seconds'), $storedObject->getCurrentVersion()->getFilename()));
|
||||
|
||||
$normalizer = new StoredObjectNormalizer($jwtProvider, $urlGenerator, $security, $tempUrlGenerator);
|
||||
$normalizer->setNormalizer($globalNormalizer);
|
||||
$storedObjectEditorDecisionManager = $this->prophesize(StoredObjectEditorDecisionManagerInterface::class);
|
||||
$storedObjectLockManager = $this->prophesize(StoredObjectLockManager::class);
|
||||
$storedObjectLockManager->hasLock($storedObject)->willReturn(false);
|
||||
|
||||
$normalizer = new StoredObjectNormalizer(
|
||||
$jwtProvider->reveal(),
|
||||
$urlGenerator->reveal(),
|
||||
$security->reveal(),
|
||||
$tempUrlGenerator->reveal(),
|
||||
$storedObjectEditorDecisionManager->reveal(),
|
||||
$storedObjectLockManager->reveal()
|
||||
);
|
||||
$normalizer->setNormalizer($globalNormalizer->reveal());
|
||||
|
||||
$actual = $normalizer->normalize($storedObject, 'json', ['groups' => ['read', 'read:download-link-only']]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user