示例#1
0
    def setUp(self):
        super().setUp()
        self.org = OrganizationFactory(name='MyOrg', key='myorg')
        self.course_run = CourseRunFactory(draft=True,
                                           title_override='MyCourse')
        self.course = self.course_run.course
        self.course.authoring_organizations.add(self.org)
        self.partner = self.course.partner
        self.group = GroupFactory()
        self.pc = self.make_user(email='*****@*****.**')
        self.editor = self.make_user(groups=[self.group])
        self.editor2 = self.make_user(groups=[self.group])
        self.non_editor = self.make_user(groups=[self.group])
        self.legal = self.make_user(
            groups=[Group.objects.get(name=LEGAL_TEAM_GROUP_NAME)])

        CourseEditorFactory(user=self.editor, course=self.course)
        CourseEditorFactory(user=self.editor2, course=self.course)
        OrganizationExtensionFactory(group=self.group, organization=self.org)
        OrganizationUserRoleFactory(user=self.pc,
                                    organization=self.org,
                                    role=InternalUserRole.ProjectCoordinator)

        self.publisher_url = '{}courses/{}'.format(self.partner.publisher_url,
                                                   self.course_run.course.uuid)
        self.studio_url = '{}course/{}'.format(self.partner.studio_url,
                                               self.course_run.key)
        self.admin_url = 'https://{}/admin/course_metadata/courserun/{}/change/'.format(
            self.partner.site.domain, self.course_run.id)
        self.run_num = CourseKey.from_string(self.course_run.key).run
示例#2
0
 def test_typeahead_org_course_runs_come_up_first(self):
     """ Test typeahead response to ensure org is taken into account. """
     MITx = OrganizationFactory(key='MITx')
     HarvardX = OrganizationFactory(key='HarvardX')
     mit_run = CourseRunFactory(
         authoring_organizations=[MITx, HarvardX],
         title='MIT Testing1',
         course__partner=self.partner
     )
     harvard_run = CourseRunFactory(
         authoring_organizations=[HarvardX],
         title='MIT Testing2',
         course__partner=self.partner
     )
     mit_program = ProgramFactory(
         authoring_organizations=[MITx, HarvardX],
         title='MIT Testing1',
         partner=self.partner
     )
     harvard_program = ProgramFactory(
         authoring_organizations=[HarvardX],
         title='MIT Testing2',
         partner=self.partner
     )
     response = self.get_response({'q': 'mit'})
     self.assertEqual(response.status_code, 200)
     expected = {
         'course_runs': [self.serialize_course_run_search(mit_run),
                         self.serialize_course_run_search(harvard_run)],
         'programs': [self.serialize_program_search(mit_program),
                      self.serialize_program_search(harvard_program)]
     }
     self.assertDictEqual(response.data, expected)
示例#3
0
    def test_process_node_not_whitelisted(self):
        # Set the end date in the future
        data = mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0]
        data['field_course_end_date'] = datetime.datetime.max.strftime('%s')
        OrganizationFactory.create(
            uuid=data.get('field_course_school_node', {})[0].get('uuid'))

        config = DrupalLoaderConfigFactory.create(
            course_run_ids='SomeFakeCourseRunId',
            partner_code=self.partner.short_code,
            load_unpublished_course_runs=False)
        data_loader = DrupalCourseMarketingSiteDataLoader(
            self.partner,
            self.partner.marketing_site_url_root,
            ACCESS_TOKEN,
            'JWT',
            1,  # Make this a constant of 1 for no concurrency
            False,
            set(config.course_run_ids.split(',')),
            config.load_unpublished_course_runs)

        # Need to mock this method so that the GET isn't sent out to the test data server
        with mock.patch(
                'course_discovery.apps.publisher.dataloader.create_courses.'
                'transfer_course_image'):
            for body in mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES:
                data_loader.process_node(body)
            # Even after looping through all course bodies no new rows should be created
            course_metadata_course_run = CourseMetadataCourseRun.objects.filter(
                key=data.get('field_course_id'))
            self.assertEqual(course_metadata_course_run.count(), 0)
示例#4
0
    def test_process_node(self):
        # Set the end date in the future
        data = mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0]
        data['field_course_end_date'] = datetime.datetime.max.strftime('%s')
        OrganizationFactory.create(
            uuid=data.get('field_course_school_node', {})[0].get('uuid'))

        config = DrupalLoaderConfigFactory.create(
            course_run_ids=data.get('field_course_id'),
            partner_code=self.partner.short_code,
            load_unpublished_course_runs=False)
        data_loader = DrupalCourseMarketingSiteDataLoader(
            self.partner,
            self.partner.marketing_site_url_root,
            ACCESS_TOKEN,
            'JWT',
            1,  # Make this a constant of 1 for no concurrency
            False,
            set(config.course_run_ids.split(',')),
            config.load_unpublished_course_runs)

        # Need to mock this method so that the GET isn't sent out to the test data server
        with mock.patch(
                'course_discovery.apps.publisher.dataloader.create_courses.'
                'transfer_course_image'):
            data_loader.process_node(
                mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0])
            course_metadata_course_run = CourseMetadataCourseRun.objects.get(
                key=data.get('field_course_id'))
            self.assertIsNotNone(course_metadata_course_run)
            self.assertIsNotNone(course_metadata_course_run.course)
            publisher_course_run = PublisherCourseRun.objects.get(
                lms_course_id=course_metadata_course_run.key)
            self.assertIsNotNone(publisher_course_run)
            self.assertIsNotNone(publisher_course_run.course)
示例#5
0
    def setUp(self):
        super(TestMigrateCommentsToSalesforce, self).setUp()
        self.partner = PartnerFactory()
        self.user_1 = UserFactory()
        self.org_1 = OrganizationFactory(partner=self.partner)
        self.course_1 = CourseFactory(
            partner=self.partner,
            authoring_organizations=[self.org_1],
            key=self.org_1.key + '+101x',
            title='Old Title',
        )
        self.course_run_1 = CourseRunFactory(
            key='course-v1:{key}+1T2019'.format(
                key=self.course_1.key,
            ),
            course=self.course_1,
        )

        self.publisher_course_1 = PublisherCourseFactory(number='101x', title='New Title')
        self.publisher_course_1.organizations.add(self.org_1)  # pylint: disable=no-member
        self.publisher_course_run_1 = PublisherCourseRunFactory(
            course=self.publisher_course_1,
            lms_course_id='course-v1:{org}+{number}+1T2019'.format(
                org=self.org_1.key, number=self.publisher_course_1.number
            ),
        )
    def test_list_not_staff(self):
        """ Verify the endpoint returns a list of all organizations. """
        org1 = OrganizationFactory.create(partner=self.partner)
        org2 = OrganizationFactory.create(partner=self.partner)
        OrganizationFactory.create(partner=self.partner)

        extension1 = publisher_factories.OrganizationExtensionFactory(
            organization=org1)
        publisher_factories.OrganizationExtensionFactory(organization=org2)
        assign_perm(OrganizationExtension.VIEW_COURSE, extension1.group,
                    extension1)

        self.non_staff_user.groups.add(extension1.group)

        # Check Staff user get all groups
        response = self.client.get(self.list_path)

        assert response.status_code == 200
        self.assert_response_data_valid(response, Organization.objects.all())

        # Check non staff user gets 1 group
        self.client.logout()
        self.client.login(username=self.non_staff_user.username,
                          password=USER_PASSWORD)

        response = self.client.get(self.list_path)

        assert response.status_code == 200
        self.assert_response_data_valid(response, [org1])
    def test_retrieve_not_staff(self):
        """ Verify the endpoint returns a list of all organizations. """
        org1 = OrganizationFactory.create(partner=self.partner)
        org2 = OrganizationFactory.create(partner=self.partner)
        OrganizationFactory.create(partner=self.partner)
        url = reverse('api:v1:organization-detail', kwargs={'uuid': org2.uuid})

        extension1 = publisher_factories.OrganizationExtensionFactory(
            organization=org1)
        publisher_factories.OrganizationExtensionFactory(organization=org2)

        assign_perm(OrganizationExtension.VIEW_COURSE, extension1.group,
                    extension1)
        self.non_staff_user.groups.add(extension1.group)

        # Check Staff user get all groups
        response = self.client.get(url)

        assert response.status_code == 200
        self.assert_response_data_valid(response, org2, many=False)

        # Check non staff user gets 1 group
        self.client.logout()
        self.client.login(username=self.non_staff_user.username,
                          password=USER_PASSWORD)

        response = self.client.get(url)

        assert response.status_code == 404

        url = reverse('api:v1:organization-detail', kwargs={'uuid': org1.uuid})
        response = self.client.get(url)

        assert response.status_code == 200
        self.assert_response_data_valid(response, org1, many=False)
    def test_list(self):
        """ Verify the endpoint returns a list of all organizations. """
        OrganizationFactory.create_batch(3, partner=self.partner)

        with self.assertNumQueries(7):
            response = self.client.get(self.list_path)

        assert response.status_code == 200
        self.assert_response_data_valid(response, Organization.objects.all())
    def test_list(self):
        """ Verify the endpoint returns a list of all organizations. """

        OrganizationFactory.create_batch(3)

        with self.assertNumQueries(6):
            response = self.client.get(self.list_path)

        self.assertEqual(response.status_code, 200)
        self.assert_response_data_valid(response, Organization.objects.all())
示例#10
0
    def test_update_using_api(self):
        """
        Verify endpoint successfully updates a program.
        """
        program_data = self._program_data()

        response = self.client.post(self.list_path, program_data, format='json')
        assert response.status_code == 201
        program = Program.objects.last()
        assert program.courses.count() == 3
        assert program.authoring_organizations.count() == 3
        assert program.credit_backing_organizations.count() == 3

        program_detail_url = reverse('api:v1:program-detail', kwargs={'uuid': str(program.uuid)})
        program.title = '{orignal_title} Test Update'.format(orignal_title=program_data['title'])
        program_data['status'] = 'unpublished'

        course_runs = CourseRunFactory.create_batch(2)
        course_runs = [course_run.key for course_run in course_runs]
        program_data['course_runs'] = program_data['course_runs'] + course_runs

        organizations = OrganizationFactory.create_batch(3)
        organizations = [organization.key for organization in organizations]
        program_data['authoring_organizations'] = program_data['authoring_organizations'] + organizations
        program_data['credit_backing_organizations'] = program_data['credit_backing_organizations'] + organizations

        data = json.dumps(program_data)
        response = self.client.patch(program_detail_url, data, content_type='application/json')
        assert response.status_code == 200
        program = Program.objects.last()
        assert program.title == response.data['title']
        assert program.status == response.data['status']
        assert program.courses.count() == 5
        assert program.authoring_organizations.count() == 6
        assert program.credit_backing_organizations.count() == 6

        course_runs = CourseRunFactory.create_batch(2)
        course_runs = [course_run.key for course_run in course_runs]
        course_runs.append(program_data['course_runs'][0])
        program_data['course_runs'] = course_runs

        organizations = OrganizationFactory.create_batch(3)
        organizations = [organization.key for organization in organizations]
        organizations.append(program_data['authoring_organizations'][0])
        program_data['authoring_organizations'] = organizations
        program_data['credit_backing_organizations'] = organizations

        data = json.dumps(program_data)
        response = self.client.patch(program_detail_url, data, content_type='application/json')
        assert response.status_code == 200
        program = Program.objects.last()
        assert program.courses.count() == 3
        assert program.authoring_organizations.count() == 4
        assert program.credit_backing_organizations.count() == 4
 def setUp(self):
     super().setUp()
     self.partner = PartnerFactory(short_code="testx")
     self.organization = OrganizationFactory(partner=self.partner,
                                             name="testx")
     self.logo = mock.MagicMock(spec=File, name="logo")
     self.logo.name = "logo"
     self.certificate_logo = mock.MagicMock(spec=File,
                                            name="certificate_logo")
     self.certificate_logo.name = "certificate_logo"
     self.banner_image = mock.MagicMock(spec=File, name="banner_image")
     self.banner_image.name = "banner image"
示例#12
0
    def test_200(self):
        self.login_staff()
        org1 = OrganizationFactory()
        org2 = OrganizationFactory()
        program1 = self.create_program([org1])
        program2 = self.create_program([org2])
        program12 = self.create_program([org1, org2])
        programs = [program1, program2, program12]
        uuids = [program.uuid for program in programs]

        response = self.get(uuids)
        self.assertEqual(response.status_code, 200)
        fixture = json.loads(response.content.decode('utf-8'))

        # To make this tests less brittle, allow (inclusive) ranges for each model count.
        # For some models (e.g. Course) we DO care about the exact count.
        # For others (e.g. Video) we just want to make sure that they are there,
        # but that we're not loading a crazy amount of them.
        expected_count_ranges_by_model = {
            Organization: (2, 2),
            Program: (3, 3),
            Curriculum: (3, 3),
            Course: (9, 9),
            CourseRun: (12, 12),
            CurriculumCourseMembership: (6, 6),
            CurriculumCourseRunExclusion: (3, 3),
            ProgramType: (1, 1),
            SeatType: (1, 1),
            AdditionalPromoArea: (5, 15),
            Image: (20, 60),
            LevelType: (5, 15),
            Video: (20, 60),
            LanguageTag: (10, 30),
        }

        actual_appearances_by_model_label = defaultdict(set)
        for record in fixture:
            pk = record['pk']
            model_label = record['model']
            # Assert no duplicate objects
            self.assertNotIn(pk,
                             actual_appearances_by_model_label[model_label])
            actual_appearances_by_model_label[model_label].add(pk)

        for model, (min_expected,
                    max_expected) in expected_count_ranges_by_model.items():
            model_label = model._meta.label_lower
            actual_count = len(actual_appearances_by_model_label[model_label])
            err_string = "object count of {} for {} outside expected range [{}, {}]".format(
                actual_count, model_label, min_expected, max_expected)
            self.assertGreaterEqual(actual_count, min_expected, err_string)
            self.assertLessEqual(actual_count, max_expected, err_string)
class AddLogosToOrganizationTest(TestCase):
    def setUp(self):
        super().setUp()
        self.partner = PartnerFactory(short_code="testx")
        self.organization = OrganizationFactory(partner=self.partner,
                                                name="testx")
        self.logo = mock.MagicMock(spec=File, name="logo")
        self.logo.name = "logo"
        self.certificate_logo = mock.MagicMock(spec=File,
                                               name="certificate_logo")
        self.certificate_logo.name = "certificate_logo"
        self.banner_image = mock.MagicMock(spec=File, name="banner_image")
        self.banner_image.name = "banner image"

    def test_partner_not_found(self):
        with pytest.raises(Exception):
            call_command(Command())

    def test_image_paths_not_found(self):
        with pytest.raises(Exception):
            call_command(
                Command(),
                partner="testx",
            )

    @pytest.mark.django_db
    def test_two_organizations_with_same_partner_returns_correct_org(self):
        new_org = OrganizationFactory(partner=self.partner, name="notx")
        assert len(Organization.objects.all()) > 1
        self.organization.logo_image = None
        new_org.logo_image = None
        with mock.patch(
                "course_discovery.apps.course_metadata.management.commands.add_logos_to_organization.Command._open_assets",
                return_value={
                    "logo": self.logo,
                    "certificate_logo": self.certificate_logo,
                    "banner_image": self.banner_image,
                },
        ):
            call_command(
                Command(),
                partner="testx",
                logo="/",
                certificate_logo="/",
                banner_image="/",
            )
            self.organization.refresh_from_db()
            assert "/media/organization/logos/" in self.organization.logo_image.path
示例#14
0
    def test_ingest_respects_partner(self):
        """
        Existing organizations with the same key but linked to different partners
        shouldn't cause organization data loading to fail.
        """
        api_data = self.mock_api()
        key = api_data[1]['short_name']

        OrganizationFactory(key=key, partner=self.partner)
        OrganizationFactory(key=key)

        assert Organization.objects.count() == 2

        self.loader.ingest()

        assert Organization.objects.count() == len(api_data) + 1
示例#15
0
 def test_404_nonexistent(self):
     self.login_staff()
     program = self.create_program([OrganizationFactory()])
     bad_uuid = 'e9222eb7-7218-4a8b-9dff-b42bafbf6ed7'
     with self.assertNumQueries(self.queries(1)):
         response = self.get([program.uuid, bad_uuid])
     self.assertEqual(response.status_code, 404)
示例#16
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
示例#17
0
    def test_search_single(self):
        org = OrganizationFactory()
        course = CourseFactory(authoring_organizations=[org])
        person1 = PersonFactory(partner=self.partner)
        person2 = PersonFactory(partner=self.partner)
        PersonFactory(partner=self.partner)
        CourseRunFactory(staff=[person1, person2], course=course)

        facet_name = 'organizations_exact:{org_key}'.format(org_key=org.key)
        self.reindex_people(person1)
        self.reindex_people(person2)

        query = {'selected_facets': facet_name}
        qs = urllib.parse.urlencode(query)
        url = '{path}?{qs}'.format(path=self.path, qs=qs)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        response_data = response.json()
        self.assertEqual(response_data['objects']['count'], 2)

        query = {'selected_facets': facet_name, 'q': person1.uuid}
        qs = urllib.parse.urlencode(query)
        url = '{path}?{qs}'.format(path=self.path, qs=qs)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        response_data = response.json()
        self.assertEqual(response_data['objects']['count'], 1)
        self.assertEqual(response_data['objects']['results'][0]['uuid'],
                         str(person1.uuid))
        self.assertEqual(response_data['objects']['results'][0]['full_name'],
                         person1.full_name)
示例#18
0
    def test_publish_with_additional_organization(self, mock_access_token):
        """
        Test that the publish button does not remove existing organization
        """
        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)
        publisher_course = publisher_course_run.course
        discovery_course = discovery_course_run.course
        assert discovery_course.authoring_organizations.all().count() == 1

        publisher_course.organizations.add(OrganizationFactory())
        response = self.client.post(publish_url, {})
        assert response.status_code == 200
        assert discovery_course.authoring_organizations.all().count() == 2
示例#19
0
    def test_create_course_run_in_studio_with_image_api_failure(
            self, mock_access_token):
        organization = OrganizationFactory()
        partner = organization.partner
        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 = '{}/api/v1/course_runs/'.format(studio_url_root)
        responses.add(responses.POST, url, json=body, status=200)

        body = {'error': 'Server error'}
        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=500)

        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.exception'
        ) as mock_logger:
            publisher_course_run = CourseRunFactory(
                start=start,
                lms_course_id=None,
                course__organizations=[organization])

        assert len(responses.calls) == 2
        assert publisher_course_run.lms_course_id == course_run_key

        mock_logger.assert_called_with(
            'Failed to update Studio image for course run [%s]: %s',
            course_run_key,
            json.dumps(body).encode('utf8'))
示例#20
0
 def setUp(self):
     super(PublisherCustomCourseFormTests, self).setUp()
     self.course_form = CourseForm()
     self.organization = OrganizationFactory()
     self.course = CourseFactory(title='Test',
                                 number='a123',
                                 organizations=[self.organization])
示例#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)

        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)

        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 test_partner(self):
     """ Verify that the wrapper can return partner values. """
     organization = OrganizationFactory()
     self.course.organizations.add(organization)
     partner = "/".join(
         [org.key for org in self.course_run.course.organizations.all()])
     self.assertEqual(self.wrapped_course_run.partner, partner)
示例#23
0
 def test_organization_key(self):
     """ Verify that the wrapper return the organization key. """
     organization = OrganizationFactory()
     course_run = factories.CourseRunFactory(
         course__organizations=[organization])
     wrapped_course_run = CourseRunWrapper(course_run)
     self.assertEqual(wrapped_course_run.organization_key, organization.key)
示例#24
0
    def test_do_not_index_if_not_active(self):
        unpublished_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner,
                                                         status=ProgramStatus.Unpublished)
        unpublished_program.authoring_organizations.add(OrganizationFactory())

        retired_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner,
                                                     status=ProgramStatus.Retired)
        retired_program.authoring_organizations.add(OrganizationFactory())

        deleted_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner,
                                                     status=ProgramStatus.Deleted)
        deleted_program.authoring_organizations.add(OrganizationFactory())

        assert not unpublished_program.should_index
        assert not retired_program.should_index
        assert not deleted_program.should_index
示例#25
0
    def test_create_course_run_in_studio_with_image_failure(self, __, ___):  # pylint: disable=unused-argument
        organization = OrganizationFactory()
        partner = organization.partner
        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 = '{}/api/v1/course_runs/'.format(studio_url_root)
        responses.add(responses.POST, url, json=body, status=200)

        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.exception'
        ) as mock_logger:
            publisher_course_run = CourseRunFactory(
                start=start,
                lms_course_id=None,
                course__organizations=[organization])

        assert len(responses.calls) == 1
        assert publisher_course_run.lms_course_id == course_run_key

        mock_logger.assert_called_with(
            'Failed to update Studio image for course run [%s]',
            course_run_key)
示例#26
0
    def setUp(self):
        super(CourseRunMarkAsReviewedEmailTests, self).setUp()
        self.user = UserFactory()
        self.user_2 = UserFactory()
        self.user_3 = UserFactory()

        self.seat = factories.SeatFactory()
        self.course_run = self.seat.course_run
        self.course = self.course_run.course
        self.course.organizations.add(OrganizationFactory())

        # add user in course-user-role table
        factories.CourseUserRoleFactory(course=self.course,
                                        role=PublisherUserRole.CourseTeam,
                                        user=self.user_2)
        factories.CourseUserRoleFactory(course=self.course,
                                        role=PublisherUserRole.Publisher,
                                        user=self.user_3)
        self.course_run_state = factories.CourseRunStateFactory(
            course_run=self.course_run)

        self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
        self.course_run.save()

        toggle_switch('enable_publisher_email_notifications', True)
示例#27
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 = 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",
                                         family_name="Instructor")
        second_instructor = PersonFactory(given_name="Second",
                                          family_name="Instructor")
        self.instructors = [first_instructor, second_instructor]

        for instructor in self.instructors:
            PositionFactory(organization=self.organizations[0],
                            title="professor",
                            person=instructor)
 def test_do_not_index_if_active_course_run_is_hidden(self):
     course = self.create_course_with_basic_active_course_run()
     course.authoring_organizations.add(OrganizationFactory())
     for course_run in course.course_runs.all():
         course_run.hidden = True
         course_run.save()
     assert not course.should_index
 def test_do_not_index_if_no_url_slug(self):
     course = self.create_course_with_basic_active_course_run()
     course.authoring_organizations.add(OrganizationFactory())
     for url_slug in course.url_slug_history.all():
         url_slug.is_active = False
         url_slug.save()
     assert not course.should_index
示例#30
0
    def setUpClass(cls):
        super().setUpClass()
        cls.user = UserFactory(is_staff=True)

        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)

        for organization in cls.organizations:
            cls.organization_extensions.append(
                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)
示例#31
0
    def test_create_course_run_in_studio(self, mock_access_token):  # pylint: disable=unused-argument
        organization = OrganizationFactory()
        partner = organization.partner
        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 = '{}/api/v1/course_runs/'.format(studio_url_root)
        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)
        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.exception'
        ) as mock_logger:
            publisher_course_run = CourseRunFactory(
                start=start,
                lms_course_id=None,
                course__organizations=[organization])

            # 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
            mock_logger.assert_called_with(
                'Organization [%s] does not have an associated OrganizationExtension',
                organization.key,
            )
示例#32
0
    def test_list_uuid_filter(self):
        """ Verify the endpoint returns a list of organizations filtered by UUID. """

        organizations = OrganizationFactory.create_batch(3)

        # Test with a single UUID
        self.assert_list_uuid_filter([organizations[0]])

        # Test with multiple UUIDs
        self.assert_list_uuid_filter(organizations)
示例#33
0
    def test_data(self):
        authoring_organization, crediting_organization = OrganizationFactory.create_batch(2)
        program = ProgramFactory(authoring_organizations=[authoring_organization],
                                 credit_backing_organizations=[crediting_organization])

        # NOTE: This serializer expects SearchQuerySet results, so we run a search on the newly-created object
        # to generate such a result.
        result = SearchQuerySet().models(Program).filter(uuid=program.uuid)[0]
        serializer = ProgramSearchSerializer(result)

        expected = self._create_expected_data(program)
        self.assertDictEqual(serializer.data, expected)
示例#34
0
    def test_typeahead_authoring_organizations_partial_search(self):
        """ Test typeahead response with partial organization matching. """
        authoring_organizations = OrganizationFactory.create_batch(3)
        course_run = CourseRunFactory(authoring_organizations=authoring_organizations, course__partner=self.partner)
        program = ProgramFactory(authoring_organizations=authoring_organizations, partner=self.partner)
        partial_key = authoring_organizations[0].key[0:5]

        response = self.get_typeahead_response(partial_key)
        self.assertEqual(response.status_code, 200)
        expected = {
            'course_runs': [self.serialize_course_run(course_run)],
            'programs': [self.serialize_program(program)]
        }
        self.assertDictEqual(response.data, expected)
示例#35
0
 def test_typeahead_multiple_authoring_organizations(self):
     """ Test typeahead response with multiple authoring organizations. """
     title = "Design"
     authoring_organizations = OrganizationFactory.create_batch(3)
     course_run = CourseRunFactory(
         title=title,
         authoring_organizations=authoring_organizations,
         course__partner=self.partner
     )
     program = ProgramFactory(
         title=title, authoring_organizations=authoring_organizations,
         status=ProgramStatus.Active, partner=self.partner
     )
     response = self.get_typeahead_response(title)
     self.assertEqual(response.status_code, 200)
     response_data = response.json()
     self.assertDictEqual(response_data, {'course_runs': [self.serialize_course_run(course_run)],
                                          'programs': [self.serialize_program(program)]})
示例#36
0
    def test_list_tag_filter(self):
        """ Verify the endpoint returns a list of organizations filtered by tag. """

        tag = 'test-org'
        organizations = OrganizationFactory.create_batch(2)

        # If no organizations have been tagged, the endpoint should not return any data
        self.assert_list_tag_filter([], [tag], expected_query_count=4)

        # Tagged organizations should be returned
        organizations[0].tags.add(tag)
        self.assert_list_tag_filter([organizations[0]], [tag])

        # The endpoint should support filtering by multiple tags. The filter should be an OR filter, meaning the results
        # include any organization containing at least one of the given tags.
        tag2 = 'another-tag'
        organizations[1].tags.add(tag)
        self.assert_list_tag_filter(Organization.objects.all(), [tag, tag2])
示例#37
0
    def create_program(self):
        organizations = OrganizationFactory.create_batch(2)
        person = PersonFactory()

        courses = CourseFactory.create_batch(3)
        for course in courses:
            CourseRunFactory.create_batch(2, course=course, staff=[person], start=datetime.now())

        return ProgramFactory(
            courses=courses,
            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),
            banner_image=make_image_file('test_banner.jpg'),
            video=VideoFactory(),
            order_courses_by_start_date=False,
        )
示例#38
0
 def test_data_multiple_authoring_organizations(self):
     authoring_organizations = OrganizationFactory.create_batch(3)
     program = ProgramFactory(authoring_organizations=authoring_organizations)
     serialized_program = self.serialize_program(program)
     expected = [org.key for org in authoring_organizations]
     self.assertEqual(serialized_program.data['orgs'], expected)