示例#1
0
    def test_publish_with_staff_removed(self, mock_access_token):
        """
        Test that the publish button adds and removes staff from discovery_course_run
        """
        publisher_course_run = self._create_course_run_for_publication()

        partner = publisher_course_run.course.organizations.first().partner
        self._set_test_client_domain_and_login(partner)

        self._mock_studio_api_success(publisher_course_run)
        self._mock_ecommerce_api(publisher_course_run)

        publish_url = reverse('publisher:api:v1:course_run-publish',
                              kwargs={'pk': publisher_course_run.pk})
        response = self.client.post(publish_url, {})
        assert response.status_code == 200
        discovery_course_run = CourseRun.objects.get(
            key=publisher_course_run.lms_course_id)
        assert discovery_course_run.staff.all().count() == 2

        publisher_course_run.staff.clear()
        publisher_course_run.staff = PersonFactory.create_batch(1)
        response = self.client.post(publish_url, {})
        assert response.status_code == 200
        discovery_course_run = CourseRun.objects.get(
            key=publisher_course_run.lms_course_id)
        assert discovery_course_run.staff.all().count() == 1
示例#2
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)
示例#3
0
    def test_partial_update_staff(self):
        """ Verify partially updating allows staff updates. """
        self.mock_patch_to_studio(self.draft_course_run.key)

        p1 = PersonFactory()
        p2 = PersonFactory()
        PersonFactory()

        url = reverse('api:v1:course_run-detail',
                      kwargs={'key': self.draft_course_run.key})
        response = self.client.patch(url, {'staff': [p2.uuid, p1.uuid]},
                                     format='json')
        self.assertEqual(response.status_code, 200)

        self.draft_course_run.refresh_from_db()
        self.assertListEqual(list(self.draft_course_run.staff.all()), [p2, p1])
示例#4
0
    def setUp(self):
        super(ChangeCourseRunStateViewTests, self).setUp()
        self.seat = factories.SeatFactory(type=Seat.VERIFIED, price=2)
        self.course_run = self.seat.course_run

        self.run_state = factories.CourseRunStateFactory(name=CourseRunStateChoices.Draft, course_run=self.course_run)
        self.course_state = factories.CourseStateFactory(
            name=CourseStateChoices.Approved, course=self.course_run.course
        )
        self.user = UserFactory()
        self.user.groups.add(Group.objects.get(name=INTERNAL_USER_GROUP_NAME))

        self.change_state_url = reverse('publisher:api:change_course_run_state', kwargs={'pk': self.run_state.id})

        self.client.login(username=self.user.username, password=USER_PASSWORD)

        language_tag = LanguageTag(code='te-st', name='Test Language')
        language_tag.save()
        self.course_run.transcript_languages.add(language_tag)
        self.course_run.language = language_tag
        self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
        self.course_run.course.organizations.add(OrganizationFactory())
        self.course_run.save()

        self.course_run.staff.add(PersonFactory())

        toggle_switch('enable_publisher_email_notifications', True)
示例#5
0
    def test_sanity_check_success(self):
        """ Verify the command does not raise a CommandError error if the new index passes the sanity check. """
        CourseRunFactory.create_batch(59)
        ProgramFactory.create_batch(59)
        PersonFactory.create_batch(59)
        record_count = 60

        # Ensure that no error is raised and the sanity check passes the second time
        with mock.patch(
                'course_discovery.apps.core.utils.ElasticsearchUtils.set_alias',
                return_value=True):
            with mock.patch(
                    'course_discovery.apps.edx_elasticsearch_dsl_extensions.management.commands.'
                    'update_index.Command.get_record_count',
                    return_value=record_count):
                call_command('update_index')
示例#6
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)
    def setUp(self):
        super(CourseRunStateSerializerTests, self).setUp()
        self.run_state = CourseRunStateFactory(
            name=CourseRunStateChoices.Draft)
        self.course_run = self.run_state.course_run
        self.user = UserFactory()
        self.request.user = self.user
        CourseStateFactory(name=CourseStateChoices.Approved,
                           course=self.course_run.course)

        SeatFactory(course_run=self.course_run, type=Seat.AUDIT)
        language_tag = LanguageTag(code='te-st', name='Test Language')
        language_tag.save()
        self.course_run.transcript_languages.add(language_tag)
        self.course_run.language = language_tag
        organization = OrganizationFactory()
        self.course_run.course.organizations.add(organization)
        self.course_run.save()
        self.course_run.staff.add(PersonFactory())

        toggle_switch('enable_publisher_email_notifications', True)
        CourseUserRoleFactory(course=self.course_run.course,
                              role=PublisherUserRole.CourseTeam,
                              user=self.user)
        CourseUserRoleFactory(course=self.course_run.course,
                              role=PublisherUserRole.ProjectCoordinator,
                              user=UserFactory())
 def test_list_filter_by_slug(self):
     """ Verify the endpoint allows people to be filtered by slug. """
     person = PersonFactory()
     url = '{root}?slug={slug}'.format(root=self.people_list_url, slug=person.slug)
     response = self.client.get(url)
     self.assertEqual(response.status_code, 200)
     self.assertListEqual(response.data['results'], self.serialize_person([person], many=True))
示例#9
0
 def test_list_filter_by_slug(self):
     """ Verify the endpoint allows people to be filtered by slug. """
     with mock.patch.object(MarketingSitePeople, 'update_or_publish_person'):
         person = PersonFactory(partner=self.partner)
     url = '{root}?slug={slug}'.format(root=self.people_list_url, slug=person.slug)
     response = self.client.get(url)
     self.assertEqual(response.status_code, 200)
     self.assertListEqual(response.data['results'], self.serialize_person([person], many=True))
示例#10
0
 def test_list_different_partner(self):
     """ Verify the endpoint only shows people for the current partner. """
     with mock.patch.object(MarketingSitePeople, 'update_or_publish_person'):
         PersonFactory()  # create person for a partner that isn't self.partner; we expect this to not show up later
     response = self.client.get(self.people_list_url)
     self.assertEqual(response.status_code, 200)
     # Make sure the list does not include the new person above
     self.assertListEqual(response.data['results'], self.serialize_person([self.person], many=True))
 def setUp(self):
     super(AutoCompletePersonTests, self).setUp()
     self.user = UserFactory(is_staff=True)
     self.client.login(username=self.user.username, password=USER_PASSWORD)
     self.courses = factories.CourseFactory.create_batch(3, title='Some random course title')
     for course in self.courses:
         factories.CourseRunFactory(course=course)
     self.organizations = OrganizationFactory.create_batch(3)
     self.organization_extensions = []
     for organization in self.organizations:
         self.organization_extensions.append(factories.OrganizationExtensionFactory(organization=organization))
     self.user.groups.add(self.organization_extensions[0].group)
     first_instructor = PersonFactory(given_name="First Instructor")
     second_instructor = PersonFactory(given_name="Second Instructor")
     self.instructors = [first_instructor, second_instructor]
     for instructor in self.instructors:
         PositionFactory(organization=self.organizations[0], title="professor", person=instructor)
 def test_has_valid_staff(self):
     """ Verify that property returns True if course-run must have a staff member
     with bio and image.
     """
     self.assertFalse(self.course_run.has_valid_staff)
     staff = PersonFactory()
     self.course_run.staff.add(staff)
     self.assertTrue(self.course_run.has_valid_staff)
示例#13
0
    def create_curriculum(self, parent_program):
        person = PersonFactory()
        course = CourseFactory(partner=self.partner)
        CourseRunFactory(course=course, staff=[person])
        CourseRunFactory(course=course, staff=[person])

        curriculum = CurriculumFactory(program=parent_program)
        CurriculumCourseMembershipFactory(course=course, curriculum=curriculum)
        return curriculum
示例#14
0
 def _create_course_run_for_publication(self):
     organization = OrganizationFactory()
     transcript_languages = [LanguageTag.objects.first()]
     mock_image_file = make_image_file('test_image.jpg')
     return CourseRunFactory(course__organizations=[organization],
                             course__tertiary_subject=None,
                             course__image__from_file=mock_image_file,
                             lms_course_id='a/b/c',
                             transcript_languages=transcript_languages,
                             staff=PersonFactory.create_batch(2))
示例#15
0
 def setUp(self):
     super(PersonViewSetTests, self).setUp()
     self.user = UserFactory(is_staff=True, is_superuser=True)
     self.client.force_authenticate(self.user)
     self.person = PersonFactory()
     self.organization = OrganizationFactory()
     # DEFAULT_PARTNER_ID is used explicitly here to avoid issues with differences in
     # auto-incrementing behavior across databases. Otherwise, it's not safe to assume
     # that the partner created here will always have id=DEFAULT_PARTNER_ID.
     self.partner = PartnerFactory(id=settings.DEFAULT_PARTNER_ID)
 def test_list_filter_by_slug_unauthenticated(self):
     """ Verify the endpoint allows people to be filtered by slug, unauthenticated """
     self.client.logout()
     with mock.patch.object(MarketingSitePeople,
                            'update_or_publish_person'):
         person = PersonFactory(partner=self.partner)
     url = f'{self.people_list_url}?slug={person.slug}'
     response = self.client.get(url)
     assert response.status_code == 200
     self.assertCountEqual(response.data['results'],
                           self.serialize_person([person], many=True))
示例#17
0
 def test_list_with_org_multiple(self):
     org1 = OrganizationFactory()
     org2 = OrganizationFactory()
     course1 = CourseFactory(authoring_organizations=[org1])
     course2 = CourseFactory(authoring_organizations=[org2])
     with mock.patch.object(MarketingSitePeople, 'update_or_publish_person'):
         person1 = PersonFactory(partner=self.partner)
         person2 = PersonFactory(partner=self.partner)
         PersonFactory(partner=self.partner)
         CourseRunFactory(staff=[person1], course=course1)
         CourseRunFactory(staff=[person2], course=course2)
         url = '{url}?org={org1_key}&org={org2_key}'.format(
             url=self.people_list_url,
             org1_key=org1.key,
             org2_key=org2.key,
         )
         response = self.client.get(url)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(len(response.data['results']), 2)
         self.assertEqual(response.data['results'], self.serialize_person([person1, person2], many=True))
示例#18
0
    def create_program(self):
        organizations = [OrganizationFactory(partner=self.partner)]
        person = PersonFactory()

        course = CourseFactory(partner=self.partner)
        CourseRunFactory(course=course, staff=[person])

        program = ProgramFactory(
            courses=[course],
            authoring_organizations=organizations,
            credit_backing_organizations=organizations,
            corporate_endorsements=CorporateEndorsementFactory.create_batch(1),
            individual_endorsements=EndorsementFactory.create_batch(1),
            expected_learning_items=ExpectedLearningItemFactory.create_batch(
                1),
            job_outlook_items=JobOutlookItemFactory.create_batch(1),
            instructor_ordering=PersonFactory.create_batch(1),
            banner_image=make_image_file('test_banner.jpg'),
            video=VideoFactory(),
            partner=self.partner)
        return program
示例#19
0
 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)
示例#20
0
    def test_handle_with_push_people(self):
        DrupalPublishUuidConfigFactory(
            course_run_ids='',
            push_people=True,
        )
        person = PersonFactory()
        command = Command()

        with mock.patch.object(MarketingSitePeople, 'update_person') as cm:
            command.handle()
        self.assertEqual(cm.call_count, 1)
        self.assertEqual(cm.call_args[0][0], person)
示例#21
0
    def setUp(self):
        super(AutoCompletePersonTests, self).setUp()
        self.user = UserFactory(is_staff=True)
        self.client.login(username=self.user.username, password=USER_PASSWORD)
        self.courses = publisher_factories.CourseFactory.create_batch(
            3, title='Some random course title')

        first_instructor = PersonFactory(given_name="First",
                                         family_name="Instructor")
        second_instructor = PersonFactory(given_name="Second",
                                          family_name="Instructor")
        self.instructors = [first_instructor, second_instructor]

        self.organizations = OrganizationFactory.create_batch(3)
        self.organization_extensions = []

        for instructor in self.instructors:
            PositionFactory(organization=self.organizations[0],
                            title="professor",
                            person=instructor)

        self.course_runs = [
            publisher_factories.CourseRunFactory(course=course)
            for course in self.courses
        ]

        for organization in self.organizations:
            org_ex = publisher_factories.OrganizationExtensionFactory(
                organization=organization)
            self.organization_extensions.append(org_ex)

        disco_course = CourseFactory(
            authoring_organizations=[self.organizations[0]])
        disco_course2 = CourseFactory(
            authoring_organizations=[self.organizations[1]])
        CourseRunFactory(course=disco_course, staff=[first_instructor])
        CourseRunFactory(course=disco_course2, staff=[second_instructor])

        self.user.groups.add(self.organization_extensions[0].group)
示例#22
0
 def setUp(self):
     super(PersonViewSetTests, self).setUp()
     self.user = UserFactory()
     self.request.user = self.user
     self.target_permissions = Permission.objects.filter(
         codename__in=['add_person', 'change_person', 'delete_person'])
     self.permisson_class = ReadOnlyByPublisherUser()
     self.internal_test_group = Group.objects.create(name='internal-test')
     self.internal_test_group.permissions.add(*self.target_permissions)
     self.user.groups.add(self.internal_test_group)
     self.client.login(username=self.user.username, password=USER_PASSWORD)
     self.person = PersonFactory(partner=self.partner)
     self.organization = OrganizationFactory(partner=self.partner)
     PositionFactory(person=self.person, organization=self.organization)
     toggle_switch('publish_person_to_marketing_site', True)
     self.expected_node = {
         'resource': 'node',
         ''
         'id': '28691',
         'uuid': '18d5542f-fa80-418e-b416-455cfdeb4d4e',
         'uri': 'https://stage.edx.org/node/28691'
     }
示例#23
0
    def test_course_staff(self):
        """Verify that the wrapper return staff list."""
        staff = PersonFactory()

        # another staff with position
        staff_2 = PersonFactory()
        position = PositionFactory(person=staff_2)

        self.course_run.staff = [staff, staff_2]
        self.course_run.save()

        expected = [{
            'full_name': staff.full_name,
            'image_url': staff.get_profile_image_url,
        }, {
            'full_name': staff_2.full_name,
            'image_url': staff_2.get_profile_image_url,
            'position': position.title,
            'organization': position.organization_name
        }]

        self.assertEqual(self.wrapped_course_run.course_staff, expected)
示例#24
0
    def setUp(self):
        super(CourseRunStateTests, self).setUp()

        language_tag = LanguageTag(code='te-st', name='Test Language')
        language_tag.save()
        self.course_run.transcript_languages.add(language_tag)
        self.course_run.language = language_tag
        self.course_run.is_micromasters = True
        self.course_run.micromasters_name = 'test'
        self.course_run.save()
        self.course.course_state.name = CourseStateChoices.Approved
        self.course.save()
        self.course_run.staff.add(PersonFactory())
        self.assertTrue(self.course_run_state.can_send_for_review())
示例#25
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)
示例#26
0
    def setUpClass(cls):
        super().setUpClass()
        cls.user = UserFactory(is_staff=True)
        cls.courses = factories.CourseFactory.create_batch(
            3, title='Some random course title')

        first_instructor = PersonFactory(given_name="First",
                                         family_name="Instructor")
        second_instructor = PersonFactory(given_name="Second",
                                          family_name="Instructor")
        cls.instructors = [first_instructor, second_instructor]

        cls.organizations = OrganizationFactory.create_batch(3)
        cls.organization_extensions = []

        for instructor in cls.instructors:
            PositionFactory(organization=cls.organizations[0],
                            title="professor",
                            person=instructor)

        cls.course_runs = [
            factories.CourseRunFactory(course=course) for course in cls.courses
        ]

        for organization in cls.organizations:
            cls.organization_extensions.append(
                factories.OrganizationExtensionFactory(
                    organization=organization))

        disco_course = CourseFactory(
            authoring_organizations=[cls.organizations[0]])
        disco_course2 = CourseFactory(
            authoring_organizations=[cls.organizations[1]])
        CourseRunFactory(course=disco_course, staff=[first_instructor])
        CourseRunFactory(course=disco_course2, staff=[second_instructor])

        cls.user.groups.add(cls.organization_extensions[0].group)
示例#27
0
    def test_person_multiple_choice(self):
        """
        Verify that PersonModelMultipleChoice returns `full_name` and `profile_image_url` as choice label.
        """
        course_form = CustomCourseRunForm()
        course_form.fields['staff'].empty_label = None

        person = PersonFactory()
        course_form.fields['staff'].queryset = Person.objects.all()

        # we need to loop through choices because it is a ModelChoiceIterator
        for __, choice_label in course_form.fields['staff'].choices:
            expected = '<img src="{url}"/><span>{full_name}</span>'.format(
                full_name=person.full_name, url=person.get_profile_image_url)
            self.assertEqual(choice_label.strip(), expected)
示例#28
0
 def setUp(self):
     super(PersonViewSetTests, self).setUp()
     self.user = UserFactory(is_staff=True, is_superuser=True)
     self.user.groups.add(Group.objects.get(name=INTERNAL_USER_GROUP_NAME))
     self.client.force_authenticate(self.user)
     self.person = PersonFactory(partner=self.partner)
     self.organization = OrganizationFactory(partner=self.partner)
     PositionFactory(person=self.person, organization=self.organization)
     toggle_switch('publish_person_to_marketing_site', True)
     self.expected_node = {
         'resource': 'node',
         ''
         'id': '28691',
         'uuid': '18d5542f-fa80-418e-b416-455cfdeb4d4e',
         'uri': 'https://stage.edx.org/node/28691'
     }
示例#29
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(PersonViewSetTests, self).setUp()
     self.user = UserFactory(is_staff=True, is_superuser=True)
     self.client.force_authenticate(self.user)
     self.person = PersonFactory()
     PositionFactory(person=self.person)
     self.organization = OrganizationFactory()
     # DEFAULT_PARTNER_ID is used explicitly here to avoid issues with differences in
     # auto-incrementing behavior across databases. Otherwise, it's not safe to assume
     # that the partner created here will always have id=DEFAULT_PARTNER_ID.
     self.partner = PartnerFactory(id=settings.DEFAULT_PARTNER_ID)
     toggle_switch('publish_person_to_marketing_site', True)
     self.expected_node = {
         'resource': 'node',
         ''
         'id': '28691',
         'uuid': '18d5542f-fa80-418e-b416-455cfdeb4d4e',
         'uri': 'https://stage.edx.org/node/28691'
     }