-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] IBX-9379 Added Grace Period for archived versions #515
base: 4.6
Are you sure you want to change the base?
Changes from 4 commits
c5bace6
791fa78
ab6787e
ada2a2a
f96c82b
a8310d2
728ef2d
b339d4a
c5b3e5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,6 +129,7 @@ public function __construct( | |
// Version archive limit (0-50), only enforced on publish, not on un-publish. | ||
'default_version_archive_limit' => 5, | ||
'remove_archived_versions_on_publish' => true, | ||
'grace_period_in_seconds' => 30, | ||
]; | ||
$this->contentFilteringHandler = $contentFilteringHandler; | ||
$this->permissionResolver = $permissionService; | ||
|
@@ -381,20 +382,39 @@ public function loadContentByVersionInfo(APIVersionInfo $versionInfo, array $lan | |
public function loadContent(int $contentId, array $languages = null, ?int $versionNo = null, bool $useAlwaysAvailable = true): APIContent | ||
{ | ||
$content = $this->internalLoadContentById($contentId, $languages, $versionNo, $useAlwaysAvailable); | ||
|
||
if (!$this->permissionResolver->canUser('content', 'read', $content)) { | ||
throw new UnauthorizedException('content', 'read', ['contentId' => $contentId]); | ||
} | ||
if ( | ||
!$content->getVersionInfo()->isPublished() | ||
&& !$this->permissionResolver->canUser('content', 'versionread', $content) | ||
) { | ||
throw new UnauthorizedException('content', 'versionread', ['contentId' => $contentId, 'versionNo' => $versionNo]); | ||
if (!$this->isInGracePeriod($content, $this->settings['grace_period_in_seconds'], $versionNo)) { | ||
throw new UnauthorizedException('content', 'versionread', ['contentId' => $contentId, 'versionNo' => $versionNo]); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ad. 2. It's really useful to review SonarCloud / SonarQube analysis. https://sonarcloud.io/project/issues?sinceLeakPeriod=true&issueStatuses=OPEN%2CCONFIRMED&pullRequest=515&id=ibexa_core&open=AZWkhRnq4uuA193_QeJw There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain point 1 in more detail? I don't see a way that the grace period will grant access to a draft for a person that should be blocked by a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Essentially || ($content->getVersionInfo()->isArchived() && $this->isInGracePeriod()) costs less, performance-wise, than isInGracePeriod alone, for the cases if we're dealing with draft, not an older published version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alongosz (
$content->getVersionInfo()->isArchived()
&& --->**!**<--- $this->isInGracePeriod($content, $this->settings['grace_period_in_seconds'], $versionNo)
) ? update: either way, this breaks the solution for some reason, hard to debug why, I guess sometimes the old version is not yet in archived state? |
||
|
||
return $content; | ||
} | ||
|
||
private function isInGracePeriod(APIContent $content, int $graceSeconds, ?int $versionNo): bool | ||
{ | ||
if ($graceSeconds <= 0 || $versionNo === null) { | ||
return false; | ||
} | ||
|
||
try { | ||
$lastArchivedVersionNos = $this->persistenceHandler->contentHandler()->loadVersionNoArchivedWithin( | ||
$content->getId(), | ||
$graceSeconds | ||
); | ||
} catch (APINotFoundException $e) { | ||
return false; | ||
} | ||
|
||
return in_array($versionNo, $lastArchivedVersionNos, true); | ||
} | ||
|
||
public function internalLoadContentById( | ||
int $id, | ||
?array $languages = null, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -491,9 +491,11 @@ public function testLoadContentUnauthorized() | |
$contentService->loadContent($contentId); | ||
} | ||
|
||
public function testLoadContentNotPublishedStatusUnauthorized() | ||
public function testLoadContentNotPublishedStatusUnauthorized(bool $expectException = true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How exactly does this work? Seems this is always true, since there's no data provider or test dependency here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is leftover from when I wanted to reuse this test case with a grace period enabled, please ignore it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ok, just make sure it's dropped in the final version. I'd rather move coverage of grace period to integration tests layer. |
||
{ | ||
$this->expectException(UnauthorizedException::class); | ||
if ($expectException) { | ||
$this->expectException(UnauthorizedException::class); | ||
} | ||
|
||
$permissionResolver = $this->getPermissionResolverMock(); | ||
$contentService = $this->getPartlyMockedContentService(['internalLoadContentById']); | ||
|
@@ -3317,8 +3319,7 @@ protected function assertForTestUpdateContentNonRedundantFieldSet( | |
->expects($this->once()) | ||
->method('getCurrentUserReference') | ||
->willReturn(new UserReference(169)); | ||
$mockedService = $this->getPartlyMockedContentService(['internalLoadContentById'], $permissionResolverMock); | ||
$permissionResolverMock = $this->getPermissionResolverMock(); | ||
$mockedService = $this->getPartlyMockedContentService(['internalLoadContentById']); | ||
/** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */ | ||
$contentHandlerMock = $this->getPersistenceMock()->contentHandler(); | ||
/** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */ | ||
|
@@ -6271,7 +6272,7 @@ protected function getLocationServiceMock() | |
* | ||
* @return \Ibexa\Core\Repository\ContentService|\PHPUnit\Framework\MockObject\MockObject | ||
*/ | ||
protected function getPartlyMockedContentService(array $methods = null) | ||
protected function getPartlyMockedContentService(array $methods = null, int $gracePeriodInSeconds = 0) | ||
{ | ||
if (!isset($this->partlyMockedContentService)) { | ||
$this->partlyMockedContentService = $this->getMockBuilder(ContentService::class) | ||
|
@@ -6288,7 +6289,9 @@ protected function getPartlyMockedContentService(array $methods = null) | |
$this->getContentMapper(), | ||
$this->getContentValidatorStrategy(), | ||
$this->getContentFilteringHandlerMock(), | ||
[], | ||
[ | ||
'grace_period_in_seconds' => $gracePeriodInSeconds, | ||
], | ||
] | ||
) | ||
->getMock(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this to be "override-able" you need to:
\Ibexa\Bundle\Core\DependencyInjection\Configuration\Parser\Repository\Options::addSemanticConfig
,\Ibexa\Bundle\Core\ApiLoader\RepositoryFactory::buildRepository#L129
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a plan, yes.