Added test coverage for regions to \Drupal\Tests\experience_builder\Kernel\ApiLayoutControllerPostTest::testOutdatedAutoSave
. \Drupal\Tests\experience_builder\Kernel\ApiLayoutControllerPatchTest::test
already had a test for a conflict with a region
Change the MR so that \Drupal\experience_builder\Controller\ApiLayoutController::patch
only validates the region that contains the component being updated.
I need to add test to demonstrate how this works
updated more.... but still more to update
leaving assigned to myself
re-rolled, added some more code comments and updating the summary but not finished. Leaving assigned to myself as I am working on the summary
Postponing on ๐ [PP-1] Enforce conflict enforcement outside of tests and e2e tests Postponed because that issue end up having some back-end changes we would likely use here
tedbow โ created an issue.
We should have an explanation in the summary of the back-end/front-end interaction that leads to this problem
Postponing on ๐ Add rudimentary conflict prevention to the Config Auto-save end-point Active
changing title to make clear we are only handling content entities, node and pages with layouts
We will need this too ๐ For config entities add client support conflict detection via the `autoSaves' key Active
tedbow โ created an issue.
@jessebaker thanks for testing this. I was testing this with nodes and it was working.
Basically entity have a seperate revision id but if we create a new revision on every save this won't increment. I guess Page is not incrementing which I guess makes sense because we don't have a way to revert to old revisions or view old revisions AFIACT
So I used the "changed" time also in the revision for the client
re #13, yes I think we should postpone as that one will change how the client handles auto-saves
And then we can re-open this issue and see if the problem remains in the same way
I pushed this a little more forward I hope.
wim leers โ credited tedbow โ .
wim leers โ credited tedbow โ .
I updated the summary to acknowledge the for beta1 we are not supporting concurrent editing.
Also added ๐ Add rudimentary conflict prevention to the Config Auto-save end-point Active as a child because we have to do this for config entities too
Note I have not had time to fix the phpunit tests but the e2e test passed so that is good sign. Just to need to update the phpunit tests to expect to a nested structure with revision info from the client.
tedbow โ created an issue.
I pushed up 86ce2085 which will return the revision id under "auto" . Probably at least autoSaves: Record<string, string>;
will need to updated on the front-end because this now an object.
but it seems to work manually testing
@jessebaker I found the problem that is causing #18
It is because during Publish we delete the auto-save entry, including the hashes and the client instance id, for the items that were published. This is because there are no auto-saved information at this point. Everything matches what should have been just saved. We don't want this to show up "Review X changes"
So when the client sends the auto-saved hashes when find a mismatch, client has auto-saved hashes and the server doesn't. Now we could change the server side mechanism to stored this information separate from the actual auto-save information we will need to publish the changes but that would make the server side more complex. Also it is also possible that this particular entity will never be edited within XB again, so this keeps us from having to keep auto-saved hash information for any entity that was ever edited in XB forever.
So I was going to suggest that when submit a publish request and get response from the server that you delete the auto-save hashes. That would solve the problem in #18 but I did make me think of another problem, that actually exists right now
- User 1 open xb/xb_page/1/editor, does make any changes, there is no auto-saved hash
- User 1 leave their browser open
- User 2 opens xb/xb_page/1/editor makes some changes
- User 2 publishes xb_page 1
- User 1, makes a change in their browser session that they never closed
I think the effect would be that User 1 would make an auto-saved version that would not be aware of the published changes and so would wipe out those changes when it was published again.
We could solve this by not deleting the auto-saved entry the server-side, and therefore throwing a conflict error for User 1. But again this would require use to keep auto-save hash information forever for all entities, which could start to add up on larger sites.
So I don't think this is a solution.
I think what we need to do is have the client be aware of the starting point version of the entity it is editing.
So for example for a page or node this would be version number, vid
or changed
property.
Basically the server would return to the client, along with the "autosaves" key, a "verison_id" key of the last saved version on the server. The client would always return this key.
So in the example above User 1's last request would properly get a 409 error because it's version number would be 1 version number behind. But this would also require the client to request /xb/api/v0/layout/xb_page/1
after publishing. Though after
๐
[Meta] Selective Publishing and Reverting
Active
the client could try to be more selective and not request if the current page was not publish it would probably be safer to always just request it.
There are probably unrelated reasons why the client should always call /xb/api/v0/layout/xb_page/1
after publishing. For example Drupal has hook_entity_presave
which allows altering an entity before it is saved. Of course XB will not be aware of any changes made in custom code here, therefore if XB doesn't call /xb/api/v0/layout/xb_page/1
after publishing the auto-save request could wipe out any changes that were made in any hook_entity_presave
code
Updated summary. I changed it to major but I think it is really a product decision as to whether this acceptable for beta1 or 1.0. I definitely want surface it because I don't think we aware this problem still exists.
Unlike the data model, I don't think this likely something we couldn't fix later if the behavior is acceptable for now.
Re #12 and how this kind of problem compares to something like Workspaces that allows staging of content
I don't think Workspaces would detect if you changed an entity in workspace but then changed it back so it matched the original. So you would see "changed" entity that could be published to Live.
I think the difference you would have to submit a form at least once for this to happen, where as XB auto-save on keystrokes, so I think the editor would have much harder time figuring out what happen for unintentional changes where just want to "view" an entity XB. Even if you don't want to change a page if just want to see what the page would look like if say a JS component it uses that has changed, you have to open it up in the editor. There is no other way to just "View"
I created ๐ When in Preview mode on published page an unneeded layout POST to the back end is made Active to handle the specific problem. This issue will handle problem of creating a new auto-save entry because the system does not recognize it is the same as the initial state
tedbow โ created an issue.
will update summary too
re #11 another way I am trying to think about the problem is imaging if we had been able to use Workspaces instead of I current auto-save.
Just considering Content entities., if we had workspaces and were able to make real entity revisions in the workspaces would we have the problem of not being able to detect when the revisions in the workspace are actually the same as the revision in the live site?
Not considering XB, in standard workspaces if you edited the title of node in a workspace from "Original title" to "Updated title" back to "Original title". Not sure?
@larowlan re #10 I agree we shouldn't need to make post requests until something changes but also we should be able to make post requests and not create an auto-save entries if the form represents that same data as the save entity. Extra posts requests should not matter in that regard.
We should be able to change the form to something different to what is saved, and then change the form back to what is saved in the entity and then that should delete auto-save entry because the system detects the match.
The extra post requests seem like a minor problem but the inability to detect when a state matches the saved entity seems critical
re #9
I can't remember if we consider not relying on the form state but instead relying what would be saved if we published. Would it be possible to run \Drupal\experience_builder\ClientDataToEntityConverter::convert()
on auto-saved entry, like we do in \Drupal\experience_builder\Controller\ApiAutoSaveController::post()
and then compare against the saved entity?
Something like
// Pluck out only the content region.
$content_region = \array_values(\array_filter($auto_save['data']['layout'], static fn(array $region) => $region['id'] === XbPageVariant::MAIN_CONTENT_REGION));
$this->clientDataToEntityConverter->convert([
'layout' => reset($content_region),
'model' => $auto_save['data']['model'],
'entity_form_fields' => $auto_save['data']['entity_form_fields'],
], $entity);
// $entity now has been updated by the auto-save state
$saved_entity = loadUnchanged($entity->id())
$auto_save_entity_hash = \hash('xxh64', \json_encode($entity->toArray(), JSON_THROW_ON_ERROR));
$saved_entity_hash = \hash('xxh64', \json_encode($saved_entity->toArray(), JSON_THROW_ON_ERROR));
// or instead of hashes could we compare all fields using `$original_field->equals($received_field)` like we do in \Drupal\experience_builder\ClientDataToEntityConverter::checkPatchFieldAccess
if ($auto_save_entity_hash !== $saved_entity hash) {
// entity should be considered changed
}
I know we there would be more to it than this and we probably have massage things, but also the form values method also seem to need a lot of massaging and seems really tricky
Just try to think of alternatives.
I think the solution I pushed should fix this for xb_pages, both problem initially reported and the problem I describe in #6 where you change the title of page and then change it back but the "Review 1 change" does not go away
but it does not fix it for articles using the xb_dev_standard
module. This is because the article have more properties that are exposed in entity_form_fields
. So this just happens to fix it for xb_pages but if we say added the menu property and widget to pages this would break it again.
Maybe the problem is the logic in \Drupal\experience_builder\Controller\ApiLayoutController::getEntityData
and \Drupal\experience_builder\ClientDataToEntityConverter::setEntityFields()
are too different
Here is a comparison between the data used to make the hashes between the initial and then call to save an updated.
hmm. actually I didn't notice \Drupal\experience_builder\AutoSave\AutoSaveManager::generateHash
has
// Remove values that only exist for retrieving form state cache during
// entity conversion and should not influence the hash.
unset(
$data['entity_form_fields']['form_build_id'],
$data['entity_form_fields']['form_id'],
$data['entity_form_fields']['form_token'],
);
which I think I added. So it must be some other key that is different. looking....
I think 2 things are going on
- For some reason just Previewing triggers a request to the Layout patch or post which can trigger an auto-save. Not sure why this is happening but it should not itself trigger an auto-save if nothing has actually changed. I might be an unnecessary call to the server but it should be safe
-
I think that actually any of our production calls to
\Drupal\experience_builder\AutoSave\AutoSaveManager::save()
fromApiLayoutController
, at least for the main entity that hasentity_form_fields
will always result in a new auto-save entity. Here is why- In
\Drupal\experience_builder\Controller\ApiLayoutController::get
we have the call to record the initial has for the entity.
// Remember the initial client-side representation of this XB-enabled // content entity (prior to auto-saves existing), to allow detecting when // an auto-save request from the client should actually be stored (i.e. // when changes are detected). $this->autoSaveManager->recordInitialClientSideRepresentation($entity, [ 'layout' => [$content_layout], 'model' => self::extractModelForSubtree($content_layout, $model), 'entity_form_fields' => $entity_form_fields, ]);
Here is example result
{ "layout": [ { "nodeType": "region", "id": "content", "name": "Content", "components": [] } ], "model": [], "entity_form_fields": { "langcode[0][value]": "en", "revision_log[0][value]": "", "title[0][value]": "Untitled page", "path[0][alias]": "", "path[0][source]": "\/page\/5", "path[0][langcode]": "en", "image[media_library_selection]": "", "description[0][value]": "" } }
Notice here we don't have
form_id
orform_*
fieldsentity_form_fields
is set via$entity_form_fields = $this->getEntityData($entity);
- Then when you have made a change and auto-save is triggered it called from
\Drupal\experience_builder\Controller\ApiLayoutController::buildPreviewRenderable
If we look at the actual auto-save entity we have
"xb_page:5:en": { "owner": { "name": "root", "avatar": null, "uri": "/user/1", "id": 1 }, "entity_type": "xb_page", "entity_id": "5", "data": { "layout": [ { "nodeType": "region", "id": "content", "name": "Content", "components": [] } ], "model": [], "entity_form_fields": { "form_build_id": "form-mmx4qbE8iQ2NvDfGMf605hckQT70LUYXRW0_OsCcaMY", "langcode[0][value]": "en", "revision_log[0][value]": "", "title[0][value]": "Untitled page11", "path[0][alias]": "/untitled-page11", "path[0][source]": "/page/5", "path[0][langcode]": "en", "image[media_library_selection]": "", "description[0][value]": "", "form_token": "Qcfk9lkWdJKbHsM87vruI-x-7SguVTEVrUCJODdGIyo", "form_id": "xb_page_form", "image-media-library-update": "Update widget", "image-media-library-open-button": "Add media", "advanced__active_tab": "" } }, "data_hash": "67a515423ee87311", "langcode": "en", "label": "Untitled page11", "updated": 1749740209 }
Notice
form_build_id
is underentity_form_fields
So because we compare the has made from
recordInitialClientSideRepresentation()
without the form fields we should always get a new auto-save entry because they will never match.
- In
so the question would be why don't we always get an auto-save entry when there is not changes. I think this is because we normally don't trigger a call to \Drupal\experience_builder\AutoSave\AutoSaveManager::save
if there are no actual changes. The call to save()
should only add a entry if there are changes.
To confirm this you can do
- Create a new page
- Change the title to "Untitled Page1"
- This results in change to the title and adds a "URL alias"
- Wait and see "Review 1 changes"
- Rename the page back to ""Untitled Page" and delete the "URL alias"
- Wait and see if "Review 1 changes" changes back to "No changes"
- It will not revert back even though the values have changed back
The auto-save entry is
"xb_page:5:en": {
"owner": {
"name": "root",
"avatar": null,
"uri": "/user/1",
"id": 1
},
"entity_type": "xb_page",
"entity_id": "5",
"data": {
"layout": [
{
"nodeType": "region",
"id": "content",
"name": "Content",
"components": []
}
],
"model": [],
"entity_form_fields": {
"form_build_id": "form-mmx4qbE8iQ2NvDfGMf605hckQT70LUYXRW0_OsCcaMY",
"langcode[0][value]": "en",
"revision_log[0][value]": "",
"title[0][value]": "Untitled page",
"path[0][alias]": "",
"path[0][source]": "/page/5",
"path[0][langcode]": "en",
"image[media_library_selection]": "",
"description[0][value]": "",
"form_token": "Qcfk9lkWdJKbHsM87vruI-x-7SguVTEVrUCJODdGIyo",
"form_id": "xb_page_form",
"image-media-library-update": "Update widget",
"image-media-library-open-button": "Add media",
"advanced__active_tab": ""
}
},
"data_hash": "bd84b24727dbf6d0",
"langcode": "en",
"label": "Untitled page",
"updated": 1749740800
}
The values are back to the "initial state" except now we have form_build_id
, form_token
etc
Not sure why this happens but appears but for some reason when viewing the preview that the auto-save is triggered.
I pushed up a debug branch I can see by retrieving /xb/api/v0/auto-saves/pending the auto-save is made during the preview before the exit.
I can also see in the call to \Drupal\experience_builder\AutoSave\AutoSaveManager::recordInitialClientSideRepresentation
which is used to save a comparison to determine if an auto-save should be made `form_build_id` and other form fields are missing. this could be the problem. Have idea to fix it
tedbow โ made their first commit to this issueโs fork.
Just wanted to make clear my comments in #16 were all with the idea that we have limited time before Beta1 - re ๐ฑ Milestone 1.0.0-beta1: Start creating non-throwaway sites Active and probably have a lot of other issues. The product decision has been made that we don't need concurrent editing in Beta1. Not sure about GA. but I assume we have a lot of other features that were prioritized in for Beta1
If we had more development resources and there weren't other features that were deemed beta blockers I would be all for getting concurrent editing in before beta1. But also if also if we made that decision won't the first order of business be defining the UX for that?
isholgueras โ credited tedbow โ .
re #13 and #14 I am currently a -1 on doing ๐ Replace the postPreview action with atomic equivalents Active because
- There is nothing in #3492065 for "User interface changes"(I just copied that part of
๐
Add rudimentary conflict prevention to the preview end-point
Active
to here now)
if we "Enable concurrent editing" there probably will be some very tricky UX problems and we should figure the desired outcomes before we start making the solutionWill concurrent editing just work perfectly and we all agree exactly what that means so there is no describe the UX? ๐
for instance what happens if I am editing props for component, which should show the updates I as type, at the same time another user does another operation that moved that operation at out of view? This would either be by the other user reorder components at the same level as mine or adding another component above it that puts my out of view. Or it could be changing the props of component above mine that changes the height.
- Is there no possibility of conflict still in that system? I understand it would be less possible because you are allowing 2 users to edit different parts of the page. But 2 users could still try to edit the same component where 1 user didn't start with the latest changes that were just auto-saved correct?
If so think a lot of the problems documented in #11 still exist just at a different level down
I think #12 out of sync requests from the same user could still be problem. Especially because we send auto-save requests as you type for single prop of single component
So I think you we wouldn't be saving time but not having to solve #11 it would just be a different level, per component
- ๐ Replace the postPreview action with atomic equivalents Active just seems more complicated so there would be more unknown unknowns. I think we are further along on the current implementation so there would less, less risk
penyaskito โ credited tedbow โ .
I think there is pontential problem with #11 5)
they have come from a single instance and thus canโt be conflicting concurrent changes.
Is this true? What if the client makes 3 request in sequence and for some reason request 1 takes a long time to connect? Basically request 2 and 3 are processed and then request 1 gets processed. Wouldn't that wipe out changes in 2 and 3? Is what I suggesting even possible, maybe on randomly sluggish networks? Maybe ok to handle this edge case?
based on @larowlan's MR approval(and double checking with him)
tedbow โ created an issue.
as per #41 I closed MR !973
It is now covered with the 2 new issues ๐ Add test coverage for access exception in \Drupal\experience_builder\ClientDataToEntityConverter::checkPatchFieldAccess Active and ๐ Fields values the user has view but not edit access can be saved to AutoSave Needs work
for #45 I think we should create a new issue. I had started this in MR 964 but for clarity lets make it's own issue
re #4
But we will also create a child issue here to ensure that "Review X changes" list request has been made in the last 10 seconds.
Created child issue ๐ Ensure that client "Review X changes" is updated periodically Active
tedbow โ created an issue.
I will update the summary.
I am investigating whether this should be postponed on ๐ [PP-1] Enforce conflict enforcement outside of tests and e2e tests Postponed
I am actually surprised that no existing e2e tests failed ๐
2 new tests failed
rapid-component-addition.cy.js
: I am not sure this can really be test reliability give the random test fails we have in e2e and this test would solely rely on timing. I am removing itauto-save-conflict.cy.js
: This was attempt to try to simulate 2 users with 2 different browser sessions having a conflict. I am not sure how to do this in cypress and searched around a little and couldn't get it to work. Someone with more experience might have better luck
There was e2e test failure on global-regions.cy.js
but I ran locally and passed
Back-end changes look good
This looks good to me but publish-validation.cy.js
has a merge conflict I tried merge locally but then this test fails. Not sure if was merge conflict resolution or something we the actual test. I am not pushing my merge because it would probably just make thing worse
Either update
ApiAutoSaveController::post()
add a new route requirement-level access check (TBD which of the two is best), which must:
- iterate over all content + config entities in the auto-save store
- throw a
CacheableAccessDeniedHttpException
if any of them fail on$entity->access(operation: 'update', return_as_object: TRUE)
- if a content entity, iterate over all changed fields, throw a
CacheableAccessDeniedHttpException
if any of them fail on$entity->get($field_name)->access(operation: 'edit', return_as_object: TRUE)
This has not been done.
I double checked changing \Drupal\Tests\experience_builder\Kernel\ApiAutoSaveControllerTest::testApiAutoSaveControllerPost
To check if user with no entity specific permission could publish entities and they could
$this->setUpCurrentUser(permissions: [
'access administration pages'
]);
$response = $this->makePublishAllRequest();
$json = json_decode($response->getContent() ?: '', TRUE);
self::assertEquals(Response::HTTP_OK, $response->getStatusCode());
self::assertEquals(['message' => \sprintf('Successfully published %d items.', $withGlobal ? 6 : 5)], $json);
Seems like we need a new issue for that
sound right
re #5 Test fail did happen
Not clear on why
Creating ๐ Fields values the user has view but not edit access can be saved to AutoSave Needs work for #41.1
Ok. I am guessing the change will make entity-form-field-types-test.cy.js
fail for the field field_xbt_comment see https://git.drupalcode.org/project/experience_builder/-/merge_requests/9...
Not sure it if is related but I did see problem with field_xbt_comment in ๐ Radio button boolean fields can sometimes can be set in page data form Active
Update the summary, not need to start the MR from the work on ๐ [PP-1] Add entity access checks to routes that deal with entities Postponed
Leaving assigned to myself. See not in summary
NOT DONE WITH SUMMARY PLEASE LET ME FINISH BEFORE ISSUE IS WORKED ON ETC(๐tedbow)
Will finish later today, there are few steps I want to explain. Then I will bring over changes from ๐ [PP-1] Add entity access checks to routes that deal with entities Postponed to start the MR
tedbow โ created an issue.
Needs work for phpstan and probably improve the tests. I think the e2e test are broken in HEAD but since this is only phpunit test changes, it could probably committed while they are still broken
tedbow โ created an issue.
re #38
I agree the scope has been blurred in this issue.
I think we should make 2 new issues out of the tests in 3494915-field-access
\Drupal\Tests\experience_builder\Kernel\ApiLayoutControllerPostTest::testEntityAccessRequired
This is meant to prove that user without access to "sticky" field cannot get it set in the auto-save. Right now this test fails in 0.x but passes in this branch. Hence we know it needs the changes in\Drupal\experience_builder\Controller\ApiLayoutController::buildPreviewRenderable
because those are the only non-changes in non-test code.I think the problem is that this will cause an e2e test to fail but right now I can't e2e test to run this MR and I can't the tests to pass on my local even on 0.x. But we can figure it out in the issue we create.
\Drupal\Tests\experience_builder\Kernel\ApiLayoutControllerPostTest::testEntityFieldAccessRequiredThrowsConstraintViolation
passes in both 0.x and the MR. So we know it doesn't need any non-test changes.also we adds test coverage that we are missing for
\Drupal\experience_builder\ClientDataToEntityConverter::checkPatchFieldAccess
where it doesthrow new AccessException("The current user is not allowed to update the field '$field_name'.");
. This seems like something we should really test.Not sure if ,
\Drupal\Tests\experience_builder\Kernel\ApiLayoutControllerPostTest::testEntityFieldAccessRequiredThrowsConstraintViolation
is exactly the right way of it should be added toClientDataToEntityConverterTest
or if we should have both but the new issue can figure that out.there is the 2nd problem that as it is not
testEntityFieldAccessRequiredThrowsConstraintViolation
also sets "sticky" and should throw an exception is that but we could add a todo to the first issue as to why we aren't using sticky
tedbow โ created an issue.
The only 2 e2e tests that are failing now are `entity-form-field-types-test.cy.js` which does pass for me locally and `media-library.cy.js` which did fail locally but I didn't see an 409 request errors in the log. So maybe these are unrelated random test errors? Not sure, retesting
I brought in the changes from ๐ Add rudimentary conflict prevention to the preview end-point Active because I made progress getting the e2e test to pass, so I thought I would the current state
chatted with @wim leers myself or others(or wim) could review. I will look at this tomorrow if it still needs review
To address @larowlan's feedback I have made this a backend only issue and follow-up handle the Frontend work. I create ๐ [PP-1] Enforce conflict enforcement outside of tests and e2e tests Postponed as follow-up
In that issue I pointed to the commits that remove the /ui
if the person tackling that wants to start from my work
tedbow โ created an issue.
so I don't forget
The 3473761-empty-slot MR has phpunit test failures I will look into.
I re-running the failed e2e tests on the other MR
#13 sounds like @wim leers was ready to merge this, so assigning back to him
I think this could probably use some other eyes on before I work more on it.
So far it is the back-end implementation I mentioned in #6.
I gave a first pass(with AI help at the front). The front-end changes work with the caveat I mention in the MR about rapid fire requests.
The last test that is failing for me locally is entity-form-field-types-test.cy.js
when the test loop through many different fields, so I am pretty sure this is because of the same problem. I could probably get the tests passing with the correct waiting on requests. I have fixed a few test this way in this issue already.
To address #12 I am just going to use UUID that will get saved with auto-save each time.
I didn't want to use an auto-incremented number because a malicious user could just guess the current ones to purposefully wipe of another users changes and save there's.
I am wondering if there will be any security concerns with sending the actual hash of the auto-save to the client.
Right now I don't think there are because we pretty much send the contents of the auto save to the client via \Drupal\experience_builder\Controller\ApiLayoutController::get
anyways, so having the hash is not giving any more information.
but after ๐ If user with less/different permissions edits a page after a user with more/different permissions data lost could occur Active we may store fields in the auto-save that user does not view or edit access to. We will then probably fitler what's in the auto-save before we send it to the client.
In that case imagine this scenario
- the only field the user does not have access to is a boolean field.
- the user knows the name of the field
- the knowledge from the source code the hash is actually of whole auto-save including the field they don't have access to.
Would it be possible for the user to reconstruct the complete auto-save data from the information they have andgenerate the has themselves, 1 time with the boolean field FALSE and 1 time with the boolean field TRUE and then just check which one matches the hash they were sent?
I know it might be an edge case but this could also work with any field that has limited number of possible values
My other thought is to just send a auto-save version number.
Initially in this issue @larowlan suggested
For each item in the model, keep a version number, initialize this to 1 when we first write to the auto-save entry for that entity.
I am not sure he was considering this or he just suggested using a version number because of security concerns or just he was referring to sub-items of the auto-save we don't have hashes already for.
This is still very rough. I will pick it back up tomorrow
Right now in the MR I have only worked on getting the 3 \Drupal\Tests\experience_builder\Kernel\ApiLayoutController*Test
classes to pass
a bunch of other things should break because they are not sending the new 'autoSaves' key back to the server. Probably all of the e2e tests should fail
working on this
I need to update the summary more and figure out the relationship to ๐ [PP-1] Add entity access checks to routes that deal with entities Postponed which I also need to review
I tagged this "Needs tests" because someone could actually write a test that confirms the problem even if don't know that actually solution yet.
tedbow โ created an issue.
This might be fixed by ๐ Publish checks validation constraints, but not form validation Active