From a2ae88fae18dab4e9e171d40f32a343fc9c21bc0 Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Mon, 26 Jan 2026 10:17:21 -0600 Subject: [PATCH 1/2] fix: add missing staff_ora_grading_url field to ORA list endpoint response --- .../instructor-v2-ora-api-spec.yaml | 7 +- lms/djangoapps/instructor/ora.py | 19 ++++++ .../instructor/tests/test_api_v2.py | 66 +++++++++++++++++++ .../instructor/views/serializers_v2.py | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml b/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml index f88c4fe4b933..a7ff3f5834de 100644 --- a/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml +++ b/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml @@ -220,6 +220,7 @@ definitions: - waiting - staff - final_grade_received + - staff_ora_grading_url properties: block_id: type: string @@ -268,7 +269,11 @@ definitions: minimum: 0 description: Responses with final grade assigned example: 20 - + staff_ora_grading_url: + type: string + format: uri + description: URL to the staff grading interface for this ORA assessment + example: "https://courses.example.com/instructor/ora_grading/block-v1:edX+DemoX+Demo_Course+type@openassessment+block@ora1" Error: type: object description: Error response diff --git a/lms/djangoapps/instructor/ora.py b/lms/djangoapps/instructor/ora.py index 5a78a1503443..b1fb7e90b574 100644 --- a/lms/djangoapps/instructor/ora.py +++ b/lms/djangoapps/instructor/ora.py @@ -1,6 +1,8 @@ """Utilities for retrieving Open Response Assessments (ORAs) data for instructor dashboards.""" from django.utils.translation import gettext as _ +from django.conf import settings + from openassessment.data import OraAggregateData from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order @@ -37,6 +39,7 @@ def get_open_response_assessment_list(course): parents_cache = {} ora_items = [] + ora_grading_base_url = getattr(settings, 'ORA_GRADING_MICROFRONTEND_URL', None) for block in openassessment_blocks: block_id = str(block.location) @@ -54,10 +57,26 @@ def get_open_response_assessment_list(course): else block.display_name ) + staff_ora_grading_url = None + + has_staff_assessment = 'staff-assessment' in block.assessment_steps + is_team_enabled = block.teams_enabled + if ora_grading_base_url and has_staff_assessment and not is_team_enabled: + # During the migration to the ORA grading microfrontend, + # only provide the grading URL for non-team assignments with staff assessment. + # This logic was based on the original implementation in instructor_dashboard: + # - lms/djangoapps/instructor/views/instructor_dashboard.py + # (_section_open_response_assessment) + # - edx-ora2: + # https://github.com/openedx/edx-ora2/blob/801fbd14ebb059ab8c5ee8d5a39c260c7f87ab81/ + # openassessment/xblock/static/js/src/lms/oa_course_items_listing.js#L73 + staff_ora_grading_url = f"{ora_grading_base_url}/{block_id}" + ora_assessment_data = { 'id': block_id, 'name': assessment_name, 'parent_name': parent_block.display_name, + 'staff_ora_grading_url': staff_ora_grading_url, **DEFAULT_ORA_METRICS, } diff --git a/lms/djangoapps/instructor/tests/test_api_v2.py b/lms/djangoapps/instructor/tests/test_api_v2.py index 3821ac0e05aa..2d2d1889b45e 100644 --- a/lms/djangoapps/instructor/tests/test_api_v2.py +++ b/lms/djangoapps/instructor/tests/test_api_v2.py @@ -958,6 +958,72 @@ def test_get_assessment_list(self): assert ora_data['waiting'] == 0 assert ora_data['staff'] == 0 assert ora_data['final_grade_received'] == 0 + assert ora_data['staff_ora_grading_url'] is None + + @patch("lms.djangoapps.instructor.ora.modulestore") + def test_get_assessment_list_includes_staff_ora_grading_url_for_non_team_assignment( + self, mock_modulestore + ): + """ + Retrieve ORA assessments and ensure staff grading URL is included + for non-team assignments with staff assessment enabled. + """ + mock_store = Mock() + + mock_assessment_block = Mock( + location=self.ora_block.location, + parent=Mock(), + teams_enabled=False, + assessment_steps=["staff-assessment"], + ) + + mock_store.get_items.return_value = [mock_assessment_block] + mock_modulestore.return_value = mock_store + + response = self.client.get(self._get_url()) + + assert response.status_code == 200 + + results = response.data["results"] + assert len(results) == 1 + + ora_data = results[0] + + assert "staff_ora_grading_url" in ora_data + assert ora_data["staff_ora_grading_url"] + + @patch("lms.djangoapps.instructor.ora.modulestore") + def test_get_assessment_list_includes_staff_ora_grading_url_for_team_assignment( + self, mock_modulestore + ): + """ + Retrieve ORA assessments and ensure staff grading URL is included + for team assignments with staff assessment enabled. + """ + mock_store = Mock() + + mock_assessment_block = Mock( + location=self.ora_block.location, + parent=Mock(), + teams_enabled=True, + display_name="Team Assignment", + assessment_steps=["staff-assessment"], + ) + + mock_store.get_items.return_value = [mock_assessment_block] + mock_modulestore.return_value = mock_store + + response = self.client.get(self._get_url()) + + assert response.status_code == 200 + + results = response.data["results"] + assert len(results) == 1 + + ora_data = results[0] + + assert "staff_ora_grading_url" in ora_data + assert ora_data["staff_ora_grading_url"] is None def test_invalid_course_id(self): """Test error handling for invalid course ID.""" diff --git a/lms/djangoapps/instructor/views/serializers_v2.py b/lms/djangoapps/instructor/views/serializers_v2.py index 414079007291..c83c42d43b6e 100644 --- a/lms/djangoapps/instructor/views/serializers_v2.py +++ b/lms/djangoapps/instructor/views/serializers_v2.py @@ -433,6 +433,7 @@ class ORASerializer(serializers.Serializer): waiting = serializers.IntegerField() staff = serializers.IntegerField() final_grade_received = serializers.IntegerField(source="done") + staff_ora_grading_url = serializers.URLField(allow_null=True) class ORASummarySerializer(serializers.Serializer): From f36cf46afab64a3a6711b9b119cd0f620d4a3a72 Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Mon, 26 Jan 2026 12:16:29 -0600 Subject: [PATCH 2/2] fixup! fix: add missing staff_ora_grading_url field to ORA list endpoint response --- .../docs/references/instructor-v2-ora-api-spec.yaml | 2 +- lms/djangoapps/instructor/ora.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml b/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml index a7ff3f5834de..c73d1e6ed244 100644 --- a/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml +++ b/lms/djangoapps/instructor/docs/references/instructor-v2-ora-api-spec.yaml @@ -273,7 +273,7 @@ definitions: type: string format: uri description: URL to the staff grading interface for this ORA assessment - example: "https://courses.example.com/instructor/ora_grading/block-v1:edX+DemoX+Demo_Course+type@openassessment+block@ora1" + example: "http://apps.local.openedx.io:1993/ora-grading/block-v1:WGU+CS002+2025_T1+type@openassessment+block@ff4f5fddf42d4b9787e69c1a8cbeb058" Error: type: object description: Error response diff --git a/lms/djangoapps/instructor/ora.py b/lms/djangoapps/instructor/ora.py index b1fb7e90b574..6198aa4c3b64 100644 --- a/lms/djangoapps/instructor/ora.py +++ b/lms/djangoapps/instructor/ora.py @@ -62,7 +62,9 @@ def get_open_response_assessment_list(course): has_staff_assessment = 'staff-assessment' in block.assessment_steps is_team_enabled = block.teams_enabled if ora_grading_base_url and has_staff_assessment and not is_team_enabled: - # During the migration to the ORA grading microfrontend, + # Always generate a URL that points to the ORA Grading Microfrontend (MFE). + # + # During the migration to the ORA microfrontend, # only provide the grading URL for non-team assignments with staff assessment. # This logic was based on the original implementation in instructor_dashboard: # - lms/djangoapps/instructor/views/instructor_dashboard.py