Skip to content
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

Open
wants to merge 4 commits into
base: 4.6
Choose a base branch
from

Conversation

mateuszbieniek
Copy link
Contributor

@mateuszbieniek mateuszbieniek commented Mar 17, 2025

🎫 Issue IBX-9379

Description:

This PR introduces a "grace period" that allows for archived versions to be accessed by the user, even when they don't have a versionread policy and the requested version was archived within X seconds from the execution of the loadContent method.
The default grace period is 30 seconds (the same as probably the most popular response timeout for web servers).
The grace period now acts as a failsafe for situations when the published version number changes in the middle of the request (please check IBX-9379 for more info).

TODO:

  • Cache invalidation (persistence/HTTP) when grace period usage was detected
  • Test coverage

@mateuszbieniek mateuszbieniek changed the title [WIP] IBX-9379 Added Grace Period for achived versions [WIP] IBX-9379 Added Grace Period for archived versions Mar 18, 2025
Copy link
Member

@adamwojs adamwojs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we limit "grace period" to only last archived version ?

@Steveb-p
Copy link
Contributor

Can we limit "grace period" to only last archived version ?

That's the thing - previous archived version is not known. There isn't any entry that indicates what it was, or at least we did not find one.

@mateuszbieniek
Copy link
Contributor Author

mateuszbieniek commented Mar 20, 2025

In theory, we can (version with archived state and "highest" modification date timestamp - but that would be more like a "best guess"), but my test shows that in extreme situations, you can have more than one version change during a request.

Copy link
Member

@alongosz alongosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it seems to me as rather a workaround that should be resolved by better cache invalidation after transaction succeeds, but I don't have an actual better solution in that regard ATM (and I know it's not trivial) 😅, so I'm leaning towards accepting your solution, provided the remarks below are addressed.

  1. Integration tests coverage is necessary for those changes to be accepted into upstream.
  2. Other remarks in diff comments:

Comment on lines 388 to 395
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]);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. That check was not only to disallow viewing "unpublished" versions, but also other drafts, even for content that hasn't been published at all. While I see that your implementation of isInGracePeriod checks indeed for archived versions, you should probably check first if content has been archived. If it hasn't then that's a normal draft someone is working on before publishing it, so it should throw unauthorized exception right away if there's no versionread policy.
  2. Try combining that nested if-if into a single chained expression following code style of L389-390.

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
or install SonarQube plugin for PHPStorm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 versionread on the first hand.

Copy link
Member

Choose a reason for hiding this comment

The 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 versionread on the first hand.

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.
Unless I'm missing something...

@@ -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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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.

@@ -491,9 +491,11 @@ public function testLoadContentUnauthorized()
$contentService->loadContent($contentId);
}

public function testLoadContentNotPublishedStatusUnauthorized()
public function testLoadContentNotPublishedStatusUnauthorized(bool $expectException = true)
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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.

ok, just make sure it's dropped in the final version. I'd rather move coverage of grace period to integration tests layer.

@mateuszbieniek
Copy link
Contributor Author

Overall it seems to me as rather a workaround that should be resolved by better cache invalidation after transaction succeeds, but I don't have an actual better solution in that regard ATM (and I know it's not trivial) 😅, so I'm leaning towards accepting your solution, provided the remarks below are addressed.

This issue is not related to cache at all, except that the outcome of this issue can mess it up.

Copy link

Copy link
Contributor

@glye glye left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tricksy problem. I agree it looks like a workaround to a problem that should have some kind of better atomic solution, but if that isn't possible, then we'll have to go for it.

It better not be possible for the end user to influcence the length of the grace period. It looks ok, but please make sure they can't extend it years back. Also it should never work on trashed content, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants