-
Notifications
You must be signed in to change notification settings - Fork 4.2k
fix: updating advance settings should update corresponding course_app #37625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Thanks for the pull request, @marslanabdulrauf! 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. Where 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. |
c3a2979 to
9254e20
Compare
a5089b3 to
456a2db
Compare
456a2db to
67a8d08
Compare
| except ValidationError: | ||
| # Failed to update the course app status, | ||
| # we ignore and let the normal flow handle updates | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that ValidationErrors are thrown by update_course_advanced_settings -- and not caught elsewhere. Shouldn't we follow the same pattern?
If not, then at the very least we should probably log a warning here? The silent catch makes it much harder to troubleshoot issues.
| ) | ||
| # enabling/disabling the course app setting also updates | ||
| # the advanced settings, so we remove it from the request data | ||
| request.data.pop(setting) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This side-effect is unfortunate and hard to understand.
| raise ValidationError({"id": "Invalid app ID"}) | ||
| is_enabled = set_course_app_enabled(course_key=course_key, app_id=app_id, enabled=enabled, user=request.user) | ||
|
|
||
| is_enabled = set_course_app_status(course_key=course_key, app_id=app_id, enabled=enabled, request=request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why all the named arguments? The set_course_app_status function has only positional arguments.
(same for the other call to set_course_app_status above)
| return enabled | ||
|
|
||
|
|
||
| def set_course_app_status(course_key, app_id, enabled, request): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request object is only useful to capture the actual user. So instead of passing the full request object, I suggest we pass just the user.
| except PluginError: | ||
| course_app = None | ||
| if not course_app or not course_app.is_available(course_key): | ||
| raise ValidationError({"id": "Invalid app ID"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest the following:
try:
course_app = CourseAppsPluginManager.get_plugin(app_id)
except PluginError:
raise ValidationError({"id": f"Invalid app ID={app_id]"})
if not course_app.is_available(course_key):
raise ValidationError({"id": f"Unavailable app ID={app_id}"})
| settings_mapping = {} | ||
|
|
||
| for plugin in super().get_available_plugins().values(): | ||
| if hasattr(plugin, 'advanced_setting_field') and plugin.advanced_setting_field: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if getattr(plugin, "advanced_setting_field", None):
...
| if not course_app or not course_app.is_available(course_key): | ||
| raise ValidationError({"id": "Invalid app ID"}) | ||
|
|
||
| return set_course_app_enabled(course_key=course_key, app_id=app_id, enabled=enabled, user=request.user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why all the named arguments?
| } | ||
| # Advanced setting field name that corresponds to this app (optional) | ||
| # Should be a string representing the field name in course advanced settings | ||
| advanced_setting_field = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the attributes in this class are typed, and this one should be as well:
advanced_setting_field: str | None = None
| if not has_studio_write_access(request.user, course_key): | ||
| self.permission_denied(request) | ||
|
|
||
| course_app_settings_map = CourseAppsPluginManager.get_course_app_settings_mapping() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several issues here:
- Why is there a big piece of code right in the middle of this otherwise simple function for a change that would happen very infrequently? At the very least, this piece of code should be in a separate function.
- But then, this separate function should not modify the
requestobject. This is a side effect that is too hard to understand. - Why are we collecting all advanced settings in a single dictionary? This looks like the wrong API to me. Instead, we could write:
apps_to_toggle:: list[tuple[str, bool]] = []
for advanced_setting, setting_enabled in request.data.items():
# note how get_advanced_app_id returns str | None
if app_id := CourseAppsPluginManager.get_advanced_app_id(advanced_setting):
course_app_enabled = setting_enabled.get("value")
if course_app_enabled is not None:
apps_to_toggle.append((app_id, course_app_enabled))
for app_id, is_enabled in apps_to_toggle:
set_course_app_status(course_key, app_id, is_enabled, request.user)
Related Ticket (Internal):
https://github.com/mitodl/hq/issues/9178
Description
This PR adds bidirectional sync for common settings that can be control from both "Pages & Resources" page and advanced settings page.
It updates:
PATCHrequest to update corresponding course_app status if existsSteps to Reproduce
Pages & Resourcessection of a courseNotesandCalculatoreach to be disabled.NotesandCalculator- both will be disabled.Expected Behavior
The two settings should match - changing the state of the setting in Advanced Settings should update the setting on Pages & Resources.
For a working example, see "Flexible peer grading for ORAs" - which links to "Force Flexible Grading for Peer ORAs" in the advanced settings. Changing the setting on Pages & Resources to disabled or enabled will change the setting in Advanced Settings to true or false.
Actual Behavior
Changing the settings for calculator and notes within Advanced Settings does not change the settings on Pages & Resources. The course will update based on what is in the Advanced Settings, meaning that there can be a mismatch between the two settings but the course will always follow the flag in the Advanced Setting.
Updating the flag in Pages & Resources will update the Advanced Settings.
Testing instructions