Add StoredObjectEditorDecisionManager with tests and interface for editability decisions

- Implemented `StoredObjectEditorDecisionManager` to assess editability of stored objects based on lock status and methods.
- Created `StoredObjectEditorDecisionManagerInterface` to define the contract for decision logic.
- Added comprehensive test suite `StoredObjectEditorDecisionManagerTest` to validate scenarios including lock absence, conflicting lock methods, and compatible WOPI locks.
This commit is contained in:
2026-04-13 12:34:47 +02:00
parent 4c86dcb9ff
commit 012dc3c27d
3 changed files with 155 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Lock;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Entity\StoredObjectLockMethodEnum;
final readonly class StoredObjectEditorDecisionManager implements StoredObjectEditorDecisionManagerInterface
{
public function __construct(private StoredObjectLockManager $lockManager) {}
public function canEdit(StoredObject $storedObject, StoredObjectLockMethodEnum $lockMethodEnum): bool
{
if (!$this->lockManager->hasLock($storedObject)) {
return true;
}
$lock = $this->lockManager->getLock($storedObject);
return StoredObjectLockMethodEnum::WOPI === $lockMethodEnum && StoredObjectLockMethodEnum::WOPI === $lock->getMethod();
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Service\Lock;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Entity\StoredObjectLockMethodEnum;
/**
* Responsible for managing decisions related to editing stored objects based on their lock status and lock methods.
*
* This class focuses solely on determining editability concerning existing locks on the stored object.
* It does not evaluate permissions.
*/
interface StoredObjectEditorDecisionManagerInterface
{
/**
* Determines if a stored object can be edited based on its lock status and the lock method.
*
* This method does not take into account the permissions to edit the stored object. Its purpose is to
* check that a future edition (and lock) will be allowed.
*
* @param StoredObject $storedObject the stored object to check for edit permissions
* @param StoredObjectLockMethodEnum $lockMethodEnum the lock method to verify against the stored object's lock
*
* @return bool returns true if the stored object can be edited, false otherwise
*/
public function canEdit(StoredObject $storedObject, StoredObjectLockMethodEnum $lockMethodEnum): bool;
}

View File

@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Tests\Service\Lock;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Entity\StoredObjectLock;
use Chill\DocStoreBundle\Entity\StoredObjectLockMethodEnum;
use Chill\DocStoreBundle\Service\Lock\StoredObjectEditorDecisionManager;
use Chill\DocStoreBundle\Service\Lock\StoredObjectLockManager;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
/**
* @internal
*
* @coversNothing
*/
class StoredObjectEditorDecisionManagerTest extends TestCase
{
use ProphecyTrait;
private ObjectProphecy|StoredObjectLockManager $lockManager;
private StoredObjectEditorDecisionManager $decisionManager;
protected function setUp(): void
{
$this->lockManager = $this->prophesize(StoredObjectLockManager::class);
$this->decisionManager = new StoredObjectEditorDecisionManager($this->lockManager->reveal());
}
public function testCanEditReturnsTrueIfNoLock(): void
{
$storedObject = $this->prophesize(StoredObject::class)->reveal();
$this->lockManager->hasLock($storedObject)->willReturn(false);
$this->assertTrue($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WEBDAV));
$this->assertTrue($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WOPI));
}
public function testCanEditReturnsFalseIfExistingLockIsWebdav(): void
{
$storedObject = $this->prophesize(StoredObject::class)->reveal();
$lock = $this->prophesize(StoredObjectLock::class);
$lock->getMethod()->willReturn(StoredObjectLockMethodEnum::WEBDAV);
$this->lockManager->hasLock($storedObject)->willReturn(true);
$this->lockManager->getLock($storedObject)->willReturn($lock->reveal());
// Always false if existing lock is Webdav
$this->assertFalse($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WEBDAV));
$this->assertFalse($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WOPI));
}
public function testCanEditReturnsTrueIfBothAreWopi(): void
{
$storedObject = $this->prophesize(StoredObject::class)->reveal();
$lock = $this->prophesize(StoredObjectLock::class);
$lock->getMethod()->willReturn(StoredObjectLockMethodEnum::WOPI);
$this->lockManager->hasLock($storedObject)->willReturn(true);
$this->lockManager->getLock($storedObject)->willReturn($lock->reveal());
$this->assertTrue($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WOPI));
}
public function testCanEditReturnsFalseIfExistingLockIsWopiButRequestedIsWebdav(): void
{
$storedObject = $this->prophesize(StoredObject::class)->reveal();
$lock = $this->prophesize(StoredObjectLock::class);
$lock->getMethod()->willReturn(StoredObjectLockMethodEnum::WOPI);
$this->lockManager->hasLock($storedObject)->willReturn(true);
$this->lockManager->getLock($storedObject)->willReturn($lock->reveal());
$this->assertFalse($this->decisionManager->canEdit($storedObject, StoredObjectLockMethodEnum::WEBDAV));
}
}