From 4fecf03874ec92e957b438d0fa89581eec6ca6b4 Mon Sep 17 00:00:00 2001 From: muzaffaryousaf Date: Tue, 16 Jun 2015 18:03:43 +0500 Subject: [PATCH] Display error message on ORA 1 components in units in Studio. TNL-2304 --- .../xmodule/combined_open_ended_module.py | 31 ++++++++++++++++- .../xmodule/xmodule/peer_grading_module.py | 34 +++++++++++++++++-- .../xmodule/tests/test_combined_open_ended.py | 19 +++++++++++ .../xmodule/tests/test_peer_grading.py | 16 +++++++++ .../studio/test_studio_with_ora_component.py | 19 +++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 7e3d1fe8cc..da1f7116d3 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -1,12 +1,14 @@ import logging -from lxml import etree +from lxml import etree from pkg_resources import resource_string from xmodule.raw_module import RawDescriptor from .x_module import XModule, module_attr from xblock.fields import Integer, Scope, String, List, Float, Boolean from xmodule.open_ended_grading_classes.combined_open_ended_modulev1 import CombinedOpenEndedV1Module, CombinedOpenEndedV1Descriptor +from xmodule.validation import StudioValidation, StudioValidationMessage + from collections import namedtuple from .fields import Date, Timedelta import textwrap @@ -472,6 +474,14 @@ class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule): for attribute in self.student_attributes: setattr(self, attribute, getattr(self.child_module, attribute)) + def validate(self): + """ + Message for either error or warning validation message/s. + + Returns message and type. Priority given to error type message. + """ + return self.descriptor.validate() + class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): """ @@ -515,3 +525,22 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): # Proxy to CombinedOpenEndedModule so that external callers don't have to know if they're working # with a module or a descriptor child_module = module_attr('child_module') + + def validate(self): + """ + Validates the state of this instance. This is the override of the general XBlock method, + and it will also ask its superclass to validate. + """ + validation = super(CombinedOpenEndedDescriptor, self).validate() + validation = StudioValidation.copy(validation) + + i18n_service = self.runtime.service(self, "i18n") + + validation.summary = StudioValidationMessage( + StudioValidationMessage.ERROR, + i18n_service.ugettext( + "ORA1 is no longer supported. To use this assessment, " + "replace this ORA1 component with an ORA2 component." + ) + ) + return validation diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 6e0da07a8f..5a5532583c 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -2,8 +2,11 @@ import json import logging from datetime import datetime + +from django.utils.timezone import UTC from lxml import etree from pkg_resources import resource_string + from xblock.fields import Dict, String, Scope, Boolean, Float, Reference from xmodule.capa_module import ComplexEncoder @@ -13,10 +16,10 @@ from xmodule.raw_module import RawDescriptor from xmodule.timeinfo import TimeInfo from xmodule.x_module import XModule, module_attr from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, MockPeerGradingService +from xmodule.open_ended_grading_classes.grading_service_module import GradingServiceError +from xmodule.validation import StudioValidation, StudioValidationMessage from open_ended_grading_classes import combined_open_ended_rubric -from django.utils.timezone import UTC -from xmodule.open_ended_grading_classes.grading_service_module import GradingServiceError log = logging.getLogger(__name__) @@ -643,6 +646,14 @@ class PeerGradingModule(PeerGradingFields, XModule): else: return True, "" + def validate(self): + """ + Message for either error or warning validation message/s. + + Returns message and type. Priority given to error type message. + """ + return self.descriptor.validate() + class PeerGradingDescriptor(PeerGradingFields, RawDescriptor): """ @@ -709,3 +720,22 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor): show_calibration_essay = module_attr('show_calibration_essay') use_for_single_location_local = module_attr('use_for_single_location_local') _find_corresponding_module_for_location = module_attr('_find_corresponding_module_for_location') + + def validate(self): + """ + Validates the state of this instance. This is the override of the general XBlock method, + and it will also ask its superclass to validate. + """ + validation = super(PeerGradingDescriptor, self).validate() + validation = StudioValidation.copy(validation) + + i18n_service = self.runtime.service(self, "i18n") + + validation.summary = StudioValidationMessage( + StudioValidationMessage.ERROR, + i18n_service.ugettext( + "ORA1 is no longer supported. To use this assessment, " + "replace this ORA1 component with an ORA2 component." + ) + ) + return validation diff --git a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py index e6a4843f99..1c880ab1dd 100644 --- a/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py +++ b/common/lib/xmodule/xmodule/tests/test_combined_open_ended.py @@ -25,7 +25,9 @@ from xmodule.combined_open_ended_module import CombinedOpenEndedModule from opaque_keys.edx.locations import Location from xmodule.tests import get_test_system, test_util_open_ended from xmodule.progress import Progress +from xmodule.validation import StudioValidationMessage from xmodule.x_module import STUDENT_VIEW + from xmodule.tests.test_util_open_ended import ( DummyModulestore, TEST_STATE_SA_IN, MOCK_INSTANCE_STATE, TEST_STATE_SA, TEST_STATE_AI, TEST_STATE_AI2, TEST_STATE_AI2_INVALID, @@ -795,6 +797,23 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): def test_state_pe_single(self): self.ai_state_success(TEST_STATE_PE_SINGLE, iscore=0, tasks=[self.task_xml2]) + def test_deprecation_message(self): + """ + Test the validation message produced for deprecation. + """ + # pylint: disable=no-member + validation = self.combinedoe_container.validate() + deprecation_msg = "ORA1 is no longer supported. To use this assessment, " \ + "replace this ORA1 component with an ORA2 component." + validation.summary.text = deprecation_msg + validation.summary.type = 'error' + + self.assertEqual( + validation.summary.text, + deprecation_msg + ) + self.assertEqual(validation.summary.type, StudioValidationMessage.ERROR) + class CombinedOpenEndedModuleConsistencyTest(unittest.TestCase): """ diff --git a/common/lib/xmodule/xmodule/tests/test_peer_grading.py b/common/lib/xmodule/xmodule/tests/test_peer_grading.py index e7df2e068d..0e895100e8 100644 --- a/common/lib/xmodule/xmodule/tests/test_peer_grading.py +++ b/common/lib/xmodule/xmodule/tests/test_peer_grading.py @@ -13,6 +13,7 @@ from xmodule.tests.test_util_open_ended import DummyModulestore from xmodule.open_ended_grading_classes.peer_grading_service import MockPeerGradingService from xmodule.peer_grading_module import PeerGradingModule, PeerGradingDescriptor, MAX_ALLOWED_FEEDBACK_LENGTH from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem +from xmodule.validation import StudioValidationMessage log = logging.getLogger(__name__) @@ -231,6 +232,21 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore): # Returning score dict. return self.peer_grading.get_score() + def test_deprecation_message(self): + """ + Test the validation message produced for deprecation. + """ + peer_grading_module = self.peer_grading + + validation = peer_grading_module.validate() + self.assertEqual(len(validation.messages), 0) + + self.assertEqual( + validation.summary.text, + "ORA1 is no longer supported. To use this assessment, replace this ORA1 component with an ORA2 component." + ) + self.assertEqual(validation.summary.type, StudioValidationMessage.ERROR) + class MockPeerGradingServiceProblemList(MockPeerGradingService): def get_problem_list(self, course_id, grader_id): diff --git a/common/test/acceptance/tests/studio/test_studio_with_ora_component.py b/common/test/acceptance/tests/studio/test_studio_with_ora_component.py index 76060bfc8c..48902d2c71 100644 --- a/common/test/acceptance/tests/studio/test_studio_with_ora_component.py +++ b/common/test/acceptance/tests/studio/test_studio_with_ora_component.py @@ -81,3 +81,22 @@ class ORAComponentTest(StudioCourseTest): location_input_element.get_attribute('value'), peer_problem_location ) + + def test_verify_ora1_deprecation_message(self): + """ + Scenario: Verifies the ora1 deprecation message on ora components. + + Given I have a course with ora 1 components + When I go to the unit page + Then I see a deprecation error message in ora 1 components. + """ + self.course_outline_page.visit() + unit = self._go_to_unit_page() + + for xblock in unit.xblocks: + self.assertTrue(xblock.has_validation_error) + self.assertEqual( + xblock.validation_error_text, + "ORA1 is no longer supported. To use this assessment, " + "replace this ORA1 component with an ORA2 component." + )