Example #1
0
    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)
Example #2
0
    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
Example #3
0
    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'))
Example #4
0
    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)
Example #5
0
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'
Example #6
0
    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')
Example #9
0
    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)
Example #10
0
    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
Example #11
0
    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())
Example #12
0
    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)
Example #13
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)