feat: add asset existence check before replacing static URLs#1708
feat: add asset existence check before replacing static URLs#1708bra-i-am wants to merge 11 commits intoopenedx:masterfrom
Conversation
|
Thanks for the pull request, @bra-i-am! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1708 +/- ##
========================================
Coverage 95.51% 95.51%
========================================
Files 1329 1330 +1
Lines 30544 30548 +4
Branches 6941 6706 -235
========================================
+ Hits 29173 29178 +5
- Misses 1303 1314 +11
+ Partials 68 56 -12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
3fb1f86 to
0123b77
Compare
0123b77 to
a630e93
Compare
|
@arbrandes, I have already addressed your comment and modified the code to implement the fix using react-query. I'm looking forward to your feedback! Thanks ✨ |
|
Thanks, @bra-i-am! I'm putting this back on my queue. I'll try to get to it before the conference, but it's possible I'll only be able to review or on after July 7th. |
|
@bra-i-am: can you help us fix the branch conflicts? Thanks! |
3d2b3dd to
2982003
Compare
|
Hi @bra-i-am! Is this pull request still in progress? |
@arbrandes @bra-i-am friendly ping on this! |
2982003 to
d23670e
Compare
|
@mphilbrick211, I solved some conflicts on this branch; the |
|
Thanks, @bra-i-am! @arbrandes are you able to take a look? |
|
Hi @bra-i-am! Is this still in progress? |
| ); | ||
| if (!isEmpty(srcs)) { | ||
| srcs.forEach(src => { | ||
| srcs.forEach(async src => { |
There was a problem hiding this comment.
Array.foreach() does not wait for callbacks to resolve, so this is going to behave unpredictably. The fact that tests didn't catch this means the tests need to be improved.
I suggest you make replaceStaticWithAsset itself asynchronous, and then use for...of instead of foreach. Callers will need to await, of course.
| let globalDefaults: { [key: string]: any } | undefined; | ||
| if (data === undefined && courseId) { | ||
| // If course-specific waffle flags were requested, first default to the | ||
| // global (studio-wide) flags until we've loaded the course-specific ones. | ||
| globalDefaults = queryClient.getQueryData(['courseDetails', undefined]); | ||
| } |
There was a problem hiding this comment.
I don't think there are global defaults for course details, right? This block can be removed.
| setEditedValues(initialEditedData); | ||
| } | ||
| }, [initialEditedData]); | ||
| }, [initialEditedData.isLoading]); |
There was a problem hiding this comment.
This means that the data is only set on initial load, not after saving.
I suggest you expose dataUpdatedAt (a react query primitive) from the query hook, then depend on that here instead of isLoading.
…CE content * fix: update image replacement in the initial value so the change is not taken as a user action
…ns and integrating new API hooks
819b293 to
4c387df
Compare
4c387df to
3b0be94
Compare
64c0e33 to
fdbadd3
Compare
|
@arbrandes, I really appreciate your help reviewing this, and thanks for your feedback. I just pushed some updates: I made the function Please let me know what you think about the changes. Thanks again! |
|
Flagging this for you, @arbrandes |
arbrandes
left a comment
There was a problem hiding this comment.
Hi @bra-i-am, thanks for sticking with it! I unleashed Claude on the PR, and it seems there are a few more things to work on:
1. React-query metadata leaks into the save API payload (bug)
useGetCourseDetails returns { ...data, id, isLoading, isError, refetch, dataUpdatedAt }. This entire object is passed as initialEditedData to useSaveValuesPrompt, which stores it in editedValues state (hooks.jsx#L43, hooks.jsx#L53).
When the user saves, editedValues is sent to the PUT API endpoint via updateWithDefaultValues(editedValues) -> updateCourseDetails(courseId, details) -> convertObjectToSnakeCase(details). This means fields like is_loading, is_error, and data_updated_at are included in the request body. refetch (a function) would be dropped by JSON serialization, but the other fields would not.
Depending on the server's behavior, this could cause validation errors or silently pass unexpected data. At minimum, these fields should be stripped before editedValues is initialized.
A clean fix would be to separate the course details data from the react-query metadata in useGetCourseDetails, or to extract only the data fields when passing to useSaveValuesPrompt.
2. 403 handling regression for course details
Previously, a 403 response when fetching course details triggered a dedicated "denied" state (RequestStatus.DENIED) that rendered a <Placeholder /> component. The base version of index.jsx checked loadingDetailsStatus === RequestStatus.DENIED.
Now, useGetCourseDetails only exposes isError (true for any error - 403, 404, 500, etc.), and the denied check only covers loadingSettingsStatus. A 403 on course details will now show a generic "load failed" alert instead of the placeholder. This is a behavior regression.
To preserve the existing behavior, the react-query hook could check error.response.status === 403 and expose it separately, or react-query's meta/onError could be used to handle it.
3. Asset validation uses GET instead of HEAD
replaceStaticWithAsset calls getAuthenticatedHttpClient().get(staticFullUrl) to check whether an asset exists. For assets that could be large (images, PDFs), this downloads the entire file just to determine existence. The asset-serving view in edx-platform (contentserver/views.py) uses Django's @require_safe decorator, which supports HEAD requests. Using .head(staticFullUrl) instead of .get() would avoid transferring the response body.
4. Whitespace: tab character in apiHooks.ts
apiHooks.ts line 22 uses a tab for dataUpdatedAt indentation instead of spaces, inconsistent with the rest of the file.
Description
This merge request solves an issue where the save warning is shown without making changes to new courses. Additionally, it also adds an existence check before replacing the static URLs
Supporting information
#1265
Testing instructions
contentstore.new_studio_mfe.use_new_schedule_details_pageCourse overviewit must be displayed the default images if the assets are not found