diff --git a/lti_consumer/lti_consumer.py b/lti_consumer/lti_consumer.py index c6ac8ba2ba7a6ab1668ad8bc0d8ac666631a8054..7d2f9553e523f876c09224f7dd48d08494aad485 100644 --- a/lti_consumer/lti_consumer.py +++ b/lti_consumer/lti_consumer.py @@ -164,6 +164,7 @@ class LaunchTarget(object): @XBlock.needs('i18n') +@XBlock.wants('lti-configuration') class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): """ This XBlock provides an LTI consumer interface for integrating @@ -421,11 +422,12 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): scope=Scope.settings ) - # StudioEditableXBlockMixin configuration of fields editable in Studio - editable_fields = ( - 'display_name', 'description', 'lti_id', 'launch_url', 'custom_parameters', 'launch_target', 'button_text', - 'inline_height', 'modal_height', 'modal_width', 'has_score', 'weight', 'hide_launch', 'accept_grades_past_due', - 'ask_to_send_username', 'ask_to_send_email' + # Possible editable fields + editable_field_names = ( + 'display_name', 'description', 'lti_id', 'launch_url', 'custom_parameters', + 'launch_target', 'button_text', 'inline_height', 'modal_height', 'modal_width', + 'has_score', 'weight', 'hide_launch', 'accept_grades_past_due', 'ask_to_send_username', + 'ask_to_send_email' ) def validate_field_data(self, validation, data): @@ -433,6 +435,30 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): _ = self.runtime.service(self, "i18n").ugettext validation.add(ValidationMessage(ValidationMessage.ERROR, unicode(_("Custom Parameters must be a list")))) + @property + def editable_fields(self): + """ + Returns editable fields which may/may not contain 'ask_to_send_username' and + 'ask_to_send_email' fields depending on the configuration service. + """ + editable_fields = self.editable_field_names + # update the editable fields if this XBlock is configured to not to allow the + # editing of 'ask_to_send_username' and 'ask_to_send_email'. + config_service = self.runtime.service(self, 'lti-configuration') + if config_service: + is_already_sharing_learner_info = self.ask_to_send_email or self.ask_to_send_username + if not config_service.configuration.lti_access_to_learners_editable( + self.course_id, + is_already_sharing_learner_info, + ): + editable_fields = tuple( + field + for field in self.editable_field_names + if field not in ('ask_to_send_username', 'ask_to_send_email') + ) + + return editable_fields + @property def descriptor(self): """ diff --git a/lti_consumer/tests/unit/test_lti_consumer.py b/lti_consumer/tests/unit/test_lti_consumer.py index e4258d554217563540d11517c39282b3f4bd7d95..141cfb0003d200692e89f91cb6d466a4507aedcb 100644 --- a/lti_consumer/tests/unit/test_lti_consumer.py +++ b/lti_consumer/tests/unit/test_lti_consumer.py @@ -263,6 +263,64 @@ class TestProperties(TestLtiConsumerXBlock): self.assertTrue(mock_timezone_now.called) +class TestEditableFields(TestLtiConsumerXBlock): + """ + Unit tests for LtiConsumerXBlock.editable_fields + """ + def get_mock_lti_configuration(self, editable): + """ + Returns a mock object of lti-configuration service + + Arguments: + editable (bool): This indicates whether the LTI fields (i.e. 'ask_to_send_username' and + 'ask_to_send_email') are editable. + """ + lti_configuration = Mock() + lti_configuration.configuration = Mock() + lti_configuration.configuration.lti_access_to_learners_editable = Mock( + return_value=editable + ) + return lti_configuration + + def are_fields_editable(self, fields): + """ + Returns whether the fields passed in as an argument, are editable. + + Arguments: + fields (list): list containing LTI Consumer XBlock's field names. + """ + return all(field in self.xblock.editable_fields for field in fields) + + def test_editable_fields_with_no_config(self): + """ + Test that LTI XBlock's fields (i.e. 'ask_to_send_username' and 'ask_to_send_email') + are editable when lti-configuration service is not provided. + """ + self.xblock.runtime.service.return_value = None + # Assert that 'ask_to_send_username' and 'ask_to_send_email' are editable. + self.assertTrue(self.are_fields_editable(fields=['ask_to_send_username', 'ask_to_send_email'])) + + def test_editable_fields_when_editing_allowed(self): + """ + Test that LTI XBlock's fields (i.e. 'ask_to_send_username' and 'ask_to_send_email') + are editable when this XBlock is configured to allow it. + """ + # this XBlock is configured to allow editing of LTI fields + self.xblock.runtime.service.return_value = self.get_mock_lti_configuration(editable=True) + # Assert that 'ask_to_send_username' and 'ask_to_send_email' are editable. + self.assertTrue(self.are_fields_editable(fields=['ask_to_send_username', 'ask_to_send_email'])) + + def test_editable_fields_when_editing_not_allowed(self): + """ + Test that LTI XBlock's fields (i.e. 'ask_to_send_username' and 'ask_to_send_email') + are not editable when this XBlock is configured to not to allow it. + """ + # this XBlock is configured to not to allow editing of LTI fields + self.xblock.runtime.service.return_value = self.get_mock_lti_configuration(editable=False) + # Assert that 'ask_to_send_username' and 'ask_to_send_email' are not editable. + self.assertFalse(self.are_fields_editable(fields=['ask_to_send_username', 'ask_to_send_email'])) + + class TestStudentView(TestLtiConsumerXBlock): """ Unit tests for LtiConsumerXBlock.student_view()