def test_course_published_email(self): """ Verify that course published email functionality works fine. """ project_coordinator = UserFactory() factories.CourseUserRoleFactory( course=self.course, role=PublisherUserRole.ProjectCoordinator, user=project_coordinator) self.course_run.lms_course_id = 'course-v1:testX+test45+2017T2' self.course_run.save() person = PersonFactory() DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, staff=[person]) emails.send_course_run_published_email(self.course_run, self.site) course_key = CourseKey.from_string(self.course_run.lms_course_id) subject = 'Publication complete: About page for {course_name} {run_number}'.format( course_name=self.course_run.course.title, run_number=course_key.run) assert len(mail.outbox) == 1 message = mail.outbox[0] assert message.to == [self.user.email] assert message.cc == [project_coordinator.email] self.assertEqual(str(mail.outbox[0].subject), subject) body = mail.outbox[0].body.strip() self.assertIn(self.course_run.preview_url, body) self.assertIn('has been published', body)
def test_create_course_run_in_studio_as_rerun(self, mock_access_token): # pylint: disable=unused-argument number = 'TestX' organization = OrganizationFactory() partner = organization.partner course_key = '{org}+{number}'.format(org=organization.key, number=number) discovery_course_run = DiscoveryCourseRunFactory( course__partner=partner, course__key=course_key) start = datetime.datetime.utcnow() course_run_key = 'course-v1:TestX+Testing101x+1T2017' body = {'id': course_run_key} studio_url_root = partner.studio_url.strip('/') url = '{root}/api/v1/course_runs/{course_run_key}/rerun/'.format( root=studio_url_root, course_run_key=discovery_course_run.key) responses.add(responses.POST, url, json=body, status=200) body = {'card_image': 'https://example.com/image.jpg'} url = '{root}/api/v1/course_runs/{course_run_key}/images/'.format( root=studio_url_root, course_run_key=course_run_key) responses.add(responses.POST, url, json=body, status=200) publisher_course_run = CourseRunFactory( start=start, lms_course_id=None, course__organizations=[organization], course__number=number) # We refresh because the signal should update the instance with the course run key from Studio publisher_course_run.refresh_from_db() assert len(responses.calls) == 2 assert publisher_course_run.lms_course_id == course_run_key
def test_create_course_run_error_with_discovery_run( self, mock_access_token): # pylint: disable=unused-argument """ Tests that course run creations raises exception and logs expected exception message """ number = 'TestX' organization = OrganizationFactory() partner = organization.partner course_key = '{org}+{number}'.format(org=organization.key, number=number) discovery_course_run = DiscoveryCourseRunFactory( course__partner=partner, course__key=course_key) body = {'error': 'Server error'} studio_url_root = partner.studio_url.strip('/') url = '{root}/api/v1/course_runs/{course_run_key}/rerun/'.format( root=studio_url_root, course_run_key=discovery_course_run.key) responses.add(responses.POST, url, json=body, status=500) with mock.patch( 'course_discovery.apps.publisher.signals.logger.exception' ) as mock_logger: with pytest.raises(HttpServerError): CourseRunFactory(lms_course_id=None, course__organizations=[organization], course__number=number) assert len(responses.calls) == 1 mock_logger.assert_called_with( 'Failed to create course run [%s] on Studio: %s', course_key, json.dumps(body).encode('utf8'))
def test_update_preview_url(self): """Verify the user can update course preview url.""" self.course_run.lms_course_id = 'course-v1:testX+TC167+2018T1' self.course_run.save() factories.CourseRunStateFactory.create(course_run=self.course_run, owner_role=PublisherUserRole.Publisher) factories.CourseUserRoleFactory( course=self.course_run.course, role=PublisherUserRole.Publisher ) course_team_role = factories.CourseUserRoleFactory( course=self.course_run.course, role=PublisherUserRole.CourseTeam ) person = PersonFactory() DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, staff=[person]) preview_url = 'https://example.com/abc/new-course-preview' response = self._make_request(preview_url) self.assertEqual(response.status_code, 200) course_run = CourseRun.objects.get(id=self.course_run.id) self.assertTrue(course_run.preview_url.endswith('/new-course-preview')) course_key = CourseKey.from_string(course_run.lms_course_id) subject = 'Review requested: Preview for {course_name} {run_number}'.format( course_name=self.course_run.course.title, run_number=course_key.run ) self.assertEqual(len(mail.outbox), 1) self.assertEqual([course_team_role.user.email], mail.outbox[0].to) self.assertEqual(str(mail.outbox[0].subject), subject)
def test_calculate_course_run_key_run_value_with_multiple_runs_per_trimester(): number = 'TestX' organization = OrganizationFactory() partner = organization.partner course_key = '{org}+{number}'.format(org=organization.key, number=number) discovery_course = DiscoveryCourseFactory(partner=partner, key=course_key) start = datetime.datetime(2017, 2, 1) DiscoveryCourseRunFactory(key='course-v1:TestX+Testing101x+1T2017', course=discovery_course) assert StudioAPI.calculate_course_run_key_run_value(number, start) == '1T2017a' DiscoveryCourseRunFactory(key='course-v1:TestX+Testing101x+1T2017a', course=discovery_course) assert StudioAPI.calculate_course_run_key_run_value(number, start) == '1T2017b'
def test_published(self): person = PersonFactory() org = OrganizationFactory() primary = DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, staff=[person], status=CourseRunStatus.Unpublished, announcement=None, course__partner=self.partner, end=None, enrollment_end=None) second = DiscoveryCourseRunFactory(course=primary.course, status=CourseRunStatus.Published, end=None, enrollment_end=None, start=(primary.start + datetime.timedelta(days=1))) third = DiscoveryCourseRunFactory(course=primary.course, status=CourseRunStatus.Published, end=datetime.datetime(2010, 1, 1, tzinfo=UTC), enrollment_end=None) primary.course.authoring_organizations.add(org) self.course.organizations.add(org) ensure_draft_world(DiscoveryCourse.objects.get(pk=primary.course.pk)) pc = UserFactory() factories.CourseUserRoleFactory(course=self.course, role=PublisherUserRole.ProjectCoordinator, user=pc) factories.OrganizationUserRoleFactory(organization=org, role=InternalUserRole.ProjectCoordinator, user=pc) self.mock_api_client() lookup_value = getattr(primary, self.publisher.unique_field) self.mock_node_retrieval(self.publisher.node_lookup_field, lookup_value) lookup_value = getattr(third, self.publisher.unique_field) self.mock_node_retrieval(self.publisher.node_lookup_field, lookup_value) self.mock_get_redirect_form() self.mock_add_redirect() self.course_run.course_run_state.name = CourseRunStateChoices.Approved self.course_run.course_run_state.change_state(CourseRunStateChoices.Published, self.user, self.site) primary.refresh_from_db() second.refresh_from_db() third.refresh_from_db() self.assertIsNotNone(primary.announcement) self.assertEqual(primary.status, CourseRunStatus.Published) self.assertEqual(second.status, CourseRunStatus.Published) # doesn't change end=None runs self.assertEqual(third.status, CourseRunStatus.Unpublished) # does change archived runs # Check email was sent (only one - from old publisher, not new publisher flow) assert len(mail.outbox) == 1 message = mail.outbox[0] self.assertTrue(message.subject.startswith('Publication complete: ')) self.assertEqual(message.to, [self.user.email]) self.assertEqual(message.cc, [pc.email])
def setUp(self): super(CourseRunSerializerTests, self).setUp() self.course_run = CourseRunFactory() self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course' self.person = PersonFactory() self.discovery_course_run = DiscoveryCourseRunFactory( key=self.course_run.lms_course_id, staff=[self.person]) self.request = RequestFactory() self.user = UserFactory() self.request.user = self.user self.course_state = CourseRunStateFactory( course_run=self.course_run, owner_role=PublisherUserRole.Publisher)
def test_update_preview_url_slug_exists(self): """ Verify we don't push to marketing if no change required """ DiscoveryCourseRunFactory( title='course') # will create the slug 'course' serializer = self.serializer_class(self.course_run, context={'request': self.request}) with self.assertRaises(Exception) as cm: serializer.update( self.course_run, {'preview_url': 'https://example.com/abc/course'}) self.assertEqual(cm.exception.args[0], 'Preview URL already in use for another course')
def _create_decline_comment(self): # First, establish a preview_url self.course_run.lms_course_id = 'course-v1:testX+testX2.0+testCourse' self.course_run.save() person = PersonFactory() DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, staff=[person]) factories.CourseRunStateFactory( course_run=self.course_run, owner_role=PublisherUserRole.CourseTeam) return self.create_comment( content_object=self.course_run, comment_type=CommentTypeChoices.Decline_Preview)
def create_discovery_course_run_with_metadata(course, metadata): """ Creates and returns a Discovery CourseRun object with course and fields specified in metadata dictionary. Arguments: course: a Course object to assign to the created Discovery CourseRun.course field metadata: a dictionary where the keys are field names and values are field values For example, metadata could be {'pacing_type': 'Instructor-paced'}. Returns: a Discovery CourseRun object """ discovery_course_run = DiscoveryCourseRunFactory(course=course, **metadata) discovery_course_run.save() return discovery_course_run
def test_course_published(self): """ Verify that publisher user can publish course run. """ # Needs to be a backing course metadata object for publish to work discovery_run = DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, status=DiscoveryCourseRunStatus.Unpublished, announcement=None) course = self.course_run.course self.run_state.name = CourseRunStateChoices.Approved self.run_state.preview_accepted = True self.run_state.save() self._assign_role(course, PublisherUserRole.Publisher, self.user) self._assign_role(course, PublisherUserRole.CourseTeam, UserFactory()) response = self.client.patch( self.change_state_url, data=json.dumps({'name': CourseRunStateChoices.Published}), content_type=JSON_CONTENT_TYPE ) self.assertEqual(response.status_code, 200) discovery_run.refresh_from_db() self.assertIsNotNone(discovery_run.announcement) self.assertEqual(discovery_run.status, DiscoveryCourseRunStatus.Published) self.run_state = CourseRunState.objects.get(course_run=self.course_run) self.assertTrue(self.run_state.is_published) self.assertEqual(len(mail.outbox), 1) self.assertEqual([course.course_team_admin.email], mail.outbox[0].to) course_key = CourseKey.from_string(self.course_run.lms_course_id) expected_subject = 'Publication complete: About page for {course_name} {run_number}'.format( course_name=course.title, run_number=course_key.run ) self.assertEqual(str(mail.outbox[0].subject), expected_subject) self.assertIn('has been published', mail.outbox[0].body.strip())
def test_update_preview_url_with_notification_disabled(self): """ Verify that no email sent on update course preview url if notification disabled by user. """ self.course_run.lms_course_id = 'course-v1:testX+TC167+2018T1' self.course_run.save() factories.CourseRunStateFactory.create(course_run=self.course_run, owner_role=PublisherUserRole.Publisher) course_team_role = factories.CourseUserRoleFactory( course=self.course_run.course, role=PublisherUserRole.CourseTeam ) factories.UserAttributeFactory(user=course_team_role.user, enable_email_notification=False) person = PersonFactory() DiscoveryCourseRunFactory(key=self.course_run.lms_course_id, staff=[person]) preview_url = 'https://example.com/abc/new-course-preview' response = self._make_request(preview_url) self.assertEqual(response.status_code, 200) course_run = CourseRun.objects.get(id=self.course_run.id) self.assertTrue(course_run.preview_url.endswith('/new-course-preview')) self.assertEqual(len(mail.outbox), 0)
def test_preview_url(self, course_id, has_preview_url): person = PersonFactory() run = DiscoveryCourseRunFactory(key='testX/test/1', staff=[person]) self.course_run.lms_course_id = course_id self.assertEqual(self.course_run.preview_url, run.marketing_url if has_preview_url else None)