Problem/Motivation

Back in #1993202: Convert system_modules_uninstall() to a Controller the module uninstall form and the corresponding confirm form were converted from a single form which switches itself out internally to a multi-step form using an expirable key-value entry. That entry has an expiration of 60 seconds. It was added to the patch over there originally (when it was still set to 120 seconds) with the comment

Time to expire is set to 2 minutes. This could be less because we only need it for the duration of the page request.

(The comment did not end up in the patch that got committed.)

The reasoning is wrong however. The key-value entry is set when the module uninstall form gets submitted and it gets read when the uninstall confirm form gets submitted. Thus, the uninstall confirm form essentially gets invalidated after 60 seconds. If you submit the uninstall confirm form then you just get redirected to the uninstall form again, without the module(s) having been uninstalled and without any error or message of any kind.

Especially in non-optimized environments the Drupal administration UI (and especially the modules form) can take quite a few seconds to load which can lead to people switching to another task until the page loading completes. Therefore, the expiration of this particular form is far more likely to hit people than other forms. Also people are not used to this behavior, because all other forms in Drupal expire only after 6 hours.

Thus, marking critical. (Seemingly) Not being able to uninstall modules makes Drupal critically broken. Since there is no warning message or anything there is no way for the user to figure out that time is running as soon the module uninstall confirm form loads.

Proposed resolution

?

Remaining tasks

User interface changes

API changes

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because modules cannot be uninstalled under certain circumstances
Issue priority Major because users with low performance environments get the impression that uninstalling modules is impossible/broken or unreliable/sometimes broken. The modularity and the ability to uninstall modules is an essential part of Drupal and it must work without ifs or buts.

Comments

xjm’s picture

Priority: Critical » Major

To me this sounds major, since there is a workaround (reload the form). Icky bug though, and good find!

tstoeckler’s picture

How does reloading the form help?

tstoeckler’s picture

Priority: Major » Critical

Marking critical again, as it's not clear what the workaround is.

Note that the known "workaround" is submitting the form in less than 60 seconds but the problem is that it's not all clear that this is the case so it's very hard if not impossible to figure out the workaround if you do not find this issue on Drupal.org. That's why I don't think that can actually be considered a workaround with any meaningful definition of that word.

dawehner’s picture

Given that the uninstall form is not like a super high frequent accessed page, I think it would be totally legit to increase the number,
but yeah I guess we should have some common pattern to show some form of message what was going on.

stefan.r’s picture

I guess the timeout could be set to 6 hours here as well, or even a week which is what we use in tempstore.

Just some ideas for the message (which we could maybe use on other forms as well):

a) ping the server when we're about to expire the data, setting the key/value expiry date into the future on every ping (though that won't work when there's no internet connection).
b) inform users on the confirmation form itself that they have X amount of time to press the confirm button (which may be confusing and raise more questions than it answers).
c) if users press the confirm button when the data is already expired, display a big red error screen that links back to the uninstall page.
d) prevent users from having a failed confirmation attempt in the first place, i.e. when they're about to time out we auto redirect them away from the confirmation page to a big red error page explaining what just happened

I would lean toward d) with a fallback to c) in case javascript breaks or the internet connection goes away, and just set the timeout to an as large as possible number so we don't have to show any unnecessary error screens anyway.

catch’s picture

Priority: Critical » Major

Note that the known "workaround" is submitting the form in less than 60 second

Yes either that, or resubmitting the form.

It's definitely an annoying bug, but it doesn't prevent uninstalling modules altogether and it's not like an entity form where there's actual data loss. Per https://www.drupal.org/core/issue-priority this is definitely major for me.

dawehner’s picture

It seems to be that we should set the time to a reasonable high value and be done with it ...

stefan.r’s picture

Status: Active » Needs review
StatusFileSize
new2.52 KB

@dawehner or even unreasonably high, as in a week? We use a week in tempstore as well...

Still, this needs an error message at least. Also the redirect didn't work when using a URL prefix.

Status: Needs review » Needs work

The last submitted patch, 8: 2475715-8.patch, failed testing.

stefan.r’s picture

Status: Needs work » Needs review
StatusFileSize
new815 bytes
new2.55 KB

Looks like Simpletest wants the redirect to be an absolute URL

Status: Needs review » Needs work

The last submitted patch, 10: 2475715-10.patch, failed testing.

Status: Needs work » Needs review

stefan.r queued 10: 2475715-10.patch for re-testing.

tstoeckler’s picture

Since the Form cache itself is only valid for 6 hours anyway, does it make sense to use that value here as well? Or am I mixing up different things?

stefan.r’s picture

Maybe someone else can confirm but I don't think this particular form is cached...

stefan.r’s picture

Title: Module uninstall confirm only works for 60 seconds after the page load » Module uninstall form does not validate correctly and breaks the confirmation form after 60 seconds

Actually there is an additional problem with the uninstall form, it doesn't validate correctly.

If we submit an empty uninstall form, it will trigger the submit hooks despite an error happening in the validation. This is because the validation error is a simple drupal_set_message() as opposed to being filed against the form, so the $form_state->setRedirect('system.modules_uninstall'); gets overwritten by $form_state->setRedirect('system.modules_uninstall_confirm'); in the submit hooks.

The current issue is about bad things happening in the transition from the uninstall form to the uninstall confirm form as well, so we can probably add a fix for this to the patch?

stefan.r’s picture

StatusFileSize
new1.47 KB
new3.03 KB

So just to summarize, the issues here were:

  1. The uninstall form didn't validate correctly and was redirecting to the confirm form even if there was an error, as the error wasn't filed against the form.
  2. The confirm form didn't validate correctly as it was redirecting to an unprefixed URL and didn't display any error message.
  3. We only gave people 60 seconds to confirm before losing the module list.
dawehner’s picture

  1. +++ b/core/modules/system/src/Form/ModulesUninstallConfirmForm.php
    @@ -135,7 +135,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    -      return new RedirectResponse('/admin/modules/uninstall');
    +      drupal_set_message($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'), 'error');
    +      return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
    

    Good idea

  2. +++ b/core/modules/system/src/Form/ModulesUninstallForm.php
    @@ -171,7 +171,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    -      drupal_set_message($this->t('No modules selected.'), 'error');
    +      $form_state->setErrorByName('uninstall', $this->t('No modules selected.'));
    

    +1

  3. +++ b/core/modules/system/src/Form/ModulesUninstallForm.php
    @@ -184,7 +184,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    -    $this->keyValueExpirable->setWithExpire($account, $uninstall, 60);
    +    $this->keyValueExpirable->setWithExpire($account, $uninstall, 604800);
     
    

    Do we have that stored somewhere accessible in form cache? Should we also document why we hav chosen that particular value?

stefan.r’s picture

StatusFileSize
new3.24 KB

Added a comment.

Status: Needs review » Needs work

The last submitted patch, 18: 2475715-18.patch, failed testing.

Status: Needs work » Needs review

isntall queued 18: 2475715-18.patch for re-testing.

stefan.r’s picture

StatusFileSize
new3.13 KB

re-roll. Also set the expiration date to 6 hours, though not sure this form even uses the form cache?

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

I guess no, but its still a fair number

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 21: 2475715-21.patch, failed testing.

Status: Needs work » Needs review

stefan.r queued 21: 2475715-21.patch for re-testing.

stefan.r’s picture

Re-queued the patch for testing because of test fail unrelated to this patch (which also occurred on other issues):

"FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] Repository checkout: failed to checkout from [git://git.drupal.org/project/drupal.git]."

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed

Committed 99e0777 and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed 99e0777 on 8.0.x
    Issue #2475715 by stefan.r, tstoeckler: Module uninstall form does not...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.