Problem/Motivation

All pagedesigner content (revisions, ...) get deleted with no prior confirmation

Steps to reproduce

Have pagedesigner 4.2.9 installed

Visit admin/modules/uninstall

Proposed resolution

Prevent that the uninstall steps run prior to uninstalling the module

Remaining tasks

Prevent that the uninstall steps run prior to uninstalling the module

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

freezernick created an issue. See original summary.

guillaumepacilly’s picture

Assigned: Unassigned » guillaumepacilly
guillaumepacilly’s picture

I dug into this. Root cause: PagedesignerUninstallValidator::validate() (added in #3608578) calls _pagedesigner_prepare_uninstall() directly — which truncates every Pagedesigner element table and deletes the module's field storages — as part of a ModuleUninstallValidatorInterface::validate() call.

The problem is that validate() isn't only invoked during an actual, confirmed uninstall. Drupal core's ModulesUninstallForm::buildForm() calls ModuleInstaller::validateUninstall() for every installed, non-required module on every plain GET request to admin/modules/uninstall, just to decide which uninstall checkboxes to disable and what reasons to show. That includes Pagedesigner. So merely opening that page runs the destructive cleanup as a side effect of rendering it, with no confirmation step at all — exactly what's reported here.

I verified this concretely in a Kernel test: calling ModuleInstaller::validateUninstall(['pagedesigner']) against the old code (i.e. just what happens when the uninstall list page renders) deletes a field storage and then crashes with Call to undefined function ...drush_backend_batch_process(), because the deletion cascades into a batch operation that assumes a Drush context.

Fix (pushed to this issue's branch, commit c13edb0f):
- PagedesignerUninstallValidator::validate() is now read-only. It only checks whether Pagedesigner still owns field storages and returns a blocking reason (with a link) if so — it no longer mutates or deletes anything.
- Added a new confirm form, PagedesignerPrepareUninstallForm (route /admin/config/pagedesigner/settings/uninstall, permission "administer pagedesigner settings"), that runs the actual purge (_pagedesigner_prepare_uninstall()) only when an admin explicitly requests and confirms it.
- Once purged, the uninstall checkbox unblocks and the module uninstalls normally via the existing pagedesigner_uninstall() hook.
- Added tests/src/Kernel/Uninstall/PagedesignerUninstallValidatorTest.php, which asserts that repeatedly calling the validator (simulating repeated page views) never touches existing content/fields, and that the validator stops blocking only after an explicit purge.

guillaumepacilly’s picture

Status: Active » Needs review

guillaumepacilly’s picture

Status: Needs review » Reviewed & tested by the community

johannes.heinzerling’s picture

+1 RTBC
I have a small nitpick for the proposed solution, that i think should not block this mr.

pagedesigner.prepare_uninstall:
...
    _permission: "administer pagedesigner settings"

The new route requires administer pagedesigner settings, while /admin/modules/uninstall requires the core permission administer modules. In most cases roles will have both or none of these permission. But in the rare case that a person has "administer modules" but not "administer pagedesigner settings" the validator will render a link which will not be usable by this person. That may be wanted but i think it would make more sense to also allow the preparation of uninstalling the module to "administer modules"

guillaumepacilly’s picture

Thanks Johannes, and you are right.
I already released the fix so I pushed your change to 4.x branche https://git.drupalcode.org/project/pagedesigner/-/commit/3f6cd3352e220f0...

This will be released with next update by the end of the month

guillaumepacilly’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

guillaumepacilly’s picture

Status: Fixed » Closed (fixed)