diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index e0bb7e21a9..1f67070d89 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -30,7 +30,7 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locator import UsageKey from xmodule.modulestore import ModuleStoreEnum -from bulk_email.models import BulkEmailFlag +from bulk_email.models import BulkEmailFlag, CourseEmail, CourseEmailTemplate from course_modes.models import CourseMode from courseware.models import StudentModule from courseware.tests.factories import ( @@ -70,6 +70,7 @@ from certificates.models import CertificateStatuses from openedx.core.djangoapps.course_groups.cohorts import set_course_cohort_settings from openedx.core.lib.xblock_utils import grade_histogram from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers +from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin from .test_tools import msk_from_problem_urlname @@ -3558,7 +3559,7 @@ class TestEntranceExamInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginE @attr(shard=1) @patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) -class TestInstructorSendEmail(SharedModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Checks that only instructors have access to email endpoints, and that these endpoints are only accessible with courses that actually exist, @@ -3645,6 +3646,43 @@ class TestInstructorSendEmail(SharedModuleStoreTestCase, LoginEnrollmentTestCase }) self.assertEqual(response.status_code, 400) + def test_send_email_with_site_template_and_from_addr(self): + site_email = self.site_configuration.values.get('course_email_from_addr') + site_template = self.site_configuration.values.get('course_email_template_name') + CourseEmailTemplate.objects.create(name=site_template) + url = reverse('send_email', kwargs={'course_id': self.course.id.to_deprecated_string()}) + response = self.client.post(url, self.full_test_message) + self.assertEqual(response.status_code, 200) + self.assertEqual(1, CourseEmail.objects.filter( + course_id=self.course.id, + sender=self.instructor, + subject=self.full_test_message['subject'], + html_message=self.full_test_message['message'], + template_name=site_template, + from_addr=site_email + ).count()) + + def test_send_email_with_org_template_and_from_addr(self): + org_email = 'fake_org@example.com' + org_template = 'fake_org_email_template' + CourseEmailTemplate.objects.create(name=org_template) + self.site_configuration.values.update({ + 'course_email_from_addr': {self.course.id.org: org_email}, + 'course_email_template_name': {self.course.id.org: org_template} + }) + self.site_configuration.save() + url = reverse('send_email', kwargs={'course_id': self.course.id.to_deprecated_string()}) + response = self.client.post(url, self.full_test_message) + self.assertEqual(response.status_code, 200) + self.assertEqual(1, CourseEmail.objects.filter( + course_id=self.course.id, + sender=self.instructor, + subject=self.full_test_message['subject'], + html_message=self.full_test_message['message'], + template_name=org_template, + from_addr=org_email + ).count()) + class MockCompletionInfo(object): """Mock for get_task_completion_info""" diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index be8e68eeaa..05f52cd170 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -110,6 +110,7 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys import InvalidKeyError from openedx.core.djangoapps.course_groups.cohorts import is_course_cohorted from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers +from openedx.core.djangoapps.content.course_overviews.models import CourseOverview log = logging.getLogger(__name__) @@ -2516,7 +2517,7 @@ def send_email(request, course_id): - 'subject' specifies email's subject - 'message' specifies email's content """ - course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) + course_id = CourseKey.from_string(course_id) if not BulkEmailFlag.feature_enabled(course_id): return HttpResponseForbidden("Email is not enabled for this course.") @@ -2530,8 +2531,22 @@ def send_email(request, course_id): # # If these are None (there is no site configuration enabled for the current site) than # the system will use normal system defaults - template_name = configuration_helpers.get_value('course_email_template_name') + course_overview = CourseOverview.get_from_id(course_id) from_addr = configuration_helpers.get_value('course_email_from_addr') + if isinstance(from_addr, dict): + # If course_email_from_addr is a dict, we are customizing + # the email template for each organization that has courses + # on the site. The dict maps from addresses by org allowing + # us to find the correct from address to use here. + from_addr = from_addr.get(course_overview.display_org_with_default) + + template_name = configuration_helpers.get_value('course_email_template_name') + if isinstance(template_name, dict): + # If course_email_template_name is a dict, we are customizing + # the email template for each organization that has courses + # on the site. The dict maps template names by org allowing + # us to find the correct template to use here. + template_name = template_name.get(course_overview.display_org_with_default) # Create the CourseEmail object. This is saved immediately, so that # any transaction that has been pending up to this point will also be diff --git a/openedx/core/djangoapps/site_configuration/tests/mixins.py b/openedx/core/djangoapps/site_configuration/tests/mixins.py index d5859991bc..3883546c74 100644 --- a/openedx/core/djangoapps/site_configuration/tests/mixins.py +++ b/openedx/core/djangoapps/site_configuration/tests/mixins.py @@ -16,7 +16,9 @@ class SiteMixin(object): site=self.site, values={ "SITE_NAME": self.site.domain, - "course_org_filter": "fakeX", + "course_email_from_addr": "fake@example.com", + "course_email_template_name": "fake_email_template", + "course_org_filter": "fakeX" } )