From @effulgentsia in #3038350-15: Deny access to all media library View Displays if there is no valid state object:
Currently in HEAD, if you go to /admin/structure/views, then for the Media Library view, in the Displays column, you see links for /admin/content/media-widget and /admin/content/media-widget-table. In HEAD, clicking on them causes an unhandled exception, coming from MediaLibraryState::validateParameters(). Because of this, when you edit the Media Library view, and one of those displays, the live preview at the bottom doesn't work.
Let's fix this, with a fail patch. I suspect that adding a !$view->preview condition the if statement in media_library_views_post_render() should be enough to correct the bug.
| Comment | File | Size | Author |
|---|---|---|---|
| #30 | interdiff-25-28.txt | 1.86 KB | nuez |
| #30 | 3060603-28.patch | 4.48 KB | nuez |
| #29 | interdiff-25-27.txt | 1.91 KB | nuez |
| #29 | 3060603-27.patch | 4.48 KB | nuez |
| #25 | interdiff_22_25.txt | 3.14 KB | nuez |
Comments
Comment #2
marcoscanoworking on it.
Comment #3
marcoscanoCouldn't quite detect if the view is in preview on that hook... Tried with something like
empty($view->live_preview), which seems to be used in other parts of core, but it doesn't work, not sure why. In any case, if we see there is no opener ID for instance, there is no point in trying to continue processing the parameters.Comment #4
marcoscanoSomehow I managed to mess up with the diff for the test-only patch above.
Here are hopefully the correct files (there is no difference on the actual patch from #3, that's why I'm keeping their filenames).
Comment #5
marcoscanoThis is a better implementation, but same idea.
Comment #7
phenaproximaI think this looks great. Fail patch and everything. RTBC!
Comment #8
alexpottOne thing I'm pondering here is whether or not this will result in hiding errors for users.
Should we re-throw the exception if $view->preview is FALSE?
I wondered about whether we should remove the early return here. It's not necessary as we do
if (!empty($query)) {later. But we can do that later if in futuremedia_library_views_post_renderdoes more.Comment #9
phenaproximaAs @marcoscano found in #3, it's not entirely clear how to detect if the view is in preview. ViewExecutable contains a property called $preview, but it's only used one place in core (in ViewExecutable::preview()). Meanwhile, there are three places in ViewExecutable.php which refer to $this->live_preview, which is not formally defined on the class. What's the difference, and which is correct? The class documentation doesn't say. Given this confusion, it seems wisest to just do nothing. Although we could log a debugging/info message -- that might be the best option.
IMHO, it reads more cleanly to return early. If it's not possible to derive the MediaLibraryState object from the request, there's nothing for the function to do; we might as well explicitly return rather than (effectively) treat $query as a success flag. If that changes later, it will be trivial to remove the early return.
Comment #10
alexpottAfter discussing more with @phenaproxima we worked out that we have a couple of issues here.
if (!empty($view->preview))- both ->live_preview and ->preview are TRUE at this point. It'd be good to also file a follow-up to deprecate live_preview or to properly discern the difference between the two.Comment #11
phenaproximaTagging for the follow-up issues.
Comment #12
phenaproximaFiled #3060852: Allow view displays to opt out of previewability and #3060855: Provide a clear way to determine if a view is being previewed to improve things in Views.
Comment #13
seanbI agree we should only catch the exception when in preview mode.
Regarding whether or not the view is previewable or not, I think that depends on what we expect from previews. Personally I think it would already help if the view shows the filters, and media items to see what the filters look like or what the view mode looks like in the library widget. The fact that the select boxes and "Insert selected" button won't work should not block users from seeing that imho.
We should probably add more explicit tests to confirm the view is actually shown as expected:
- assert 1 or more filters
- create a media item and assert it is rendered in the view
- maybe the "Insert selected" button?
Comment #14
nuezAdded a patch with:
::testWidgetAccesstest, which is about testing access. I think that's confusing and it should go in a views test.Considering the precedent of things being broken in Views Preview (e.g. bulk operations), we could accept that this results in an ajax error in the browser, since it doesn't actually affect the UI. But do me that doesn't feel right.
I think we have the following options:
Comment #15
phenaproximaLooks great! I like the fact that we're able to keep previewability -- that is surely a good thing for site builders.
Let's rephrase this comment a bit -- how about "MediaLibraryState::fromRequest() will throw an exception if the view is being previewed, since not all required query parameters will be present. But, in a preview, we don't really care about that, so catch and swallow the exception if we are in preview."
Per coding standards,
catchneeds to be on a new line.These can be combined into one line with $assert_session->elementCount().
This is a bit ambiguous. We should scope these kinds of things to the preview area. We can do that like this:
What is
$this->click()? Can we use $page->pressButton() for clarity?Should use $assert_session->elementCount() here too.
Supernit: "ajax" should be "AJAX".
This needs a comment :) Also, the
catchneeds to be on a new line.Let's use $assert_session->elementCount() here too.
Comment #16
nuezComment #17
nuezAbout the interdiff:
This is almost what @phenaproxima suggested.
Tests were failing due to missing dependencies.
Some things code sniffer picked up...I should probably revert this for the sake of clarity.
Instead of trying to catch the exception, we should probably use the expectException method here.
Another two concerns I have about leaving the AJAX error here:
The Path returns an access denied, instead of a 500 error. Is this right? There are missing parameters, maybe that should mean that it has to return a different response code. I realise that's a whole different issue, but worth asking here.
The log is registering the 403 response when people click the button. Clogging up the log with this might not be desirable.
Comment #18
nuezThe test fails, because on tear down there's a check for any pending ajax requests. Ours is stuck, so this test always fails, unless we override the tear down method. This is the only way I could figure out how to fix it. Love to hear alternative approaches.
This is becoming a bigger and bigger code smell, that makes me think we should not allow this to break in the first place, even in preview mode.
Comment #19
nuezComment #20
nuezAfter discussing this with @phenaproxima and @seanB we come to the following conclusions:
Comment #22
seanbUsing forms in views previews is a problematic thing. For example the bulk operation forms in content view also produces unexpected behaviour. My personal feeling is hiding or disabling the button could also lead to confusion, since the preview is not showing exactly the same output as it would outside of preview mode.
Interacting with the preview is another story. I think it would helpful to show a message to users that interacting with preview might lead to unexpected results or something? This is probably something that needs to be discussed with the UX team, but the "interacting with previews" issue seems to be much broader than the media library widget displays. Not sure if that is best addressed in #3060852: Allow view displays to opt out of previewability or in a separate followup issue.
Comment #23
nuezFixed a stupid mistake and some coding standards.
Comment #24
phenaproximaSome nitpicks, otherwise I'm almost entirely fine with this.
Nit: There's an empty line here that shouldn't be.
Supernit: This line is more than 80 characters long.
Should this be || (OR condition)?
I'm not a huge fan of repeating the code here, but on second thought, I'm not exactly sure what to do about it. So I guess we'll leave it as it is. I'd merely point out that there the 'else' needs to be on a new line. :)
Should say "...clicking the 'Insert selected' button,..."
Ideally, we would test both the
widgetandwidget_tabledisplays in this method, since both are used by the widget, and both should behave the same way with regard to previewability. However, if that's too tricky, I think this test is enough to prove the fix we're making in this issue.Comment #25
nuezComment #26
phenaproximaThanks! Kicking back to review so testbot can get a word in...
Comment #27
phenaproximaThanks, @nuez! This looks excellent to me. Let's land it!
Comment #28
alexpottI think this code is a bit complex and having the two calls to MediaLibraryState::fromRequest() so close to each other is a bit odd.
We can do
Comment #29
nuezThanks for the tip @alexpott. This is indeed much cleaner.
Comment #30
nuezForget that last one...
Comment #31
phenaproximaAgreed on the improved cleanliness. The reason I didn't ask for that in the first place is that (as far as I know; please correct me if I'm wrong), re-throwing an exception overwrites its backtrace, which can make debugging more difficult. But in this case, the backtrace probably won't be particularly tricky or deeply nested, since the location of the original exception will be quite close to the place where we re-throw it. So, +1 for this change, and I'm returning this to RTBC once testbot is green.
Comment #32
alexpottCommitted and pushed 6e594c260b to 8.8.x and 699a4314df to 8.7.x. Thanks!
Comment #35
rosinegrean commented