Пример #1
0
    def test_create(self):
        """
        Create a course.
        """
        before = course_count()
        course = create_course(**self.kwargs)
        after = course_count()
        self.assertTrue(after == before + 1)
        self.assertTrue(course is not None)

        # Can't create a duplicate.
        with self.assertRaises(ValueError):
            create_course(**self.kwargs)
        self.assertTrue(course_count() == after)
Пример #2
0
def import_course(bundle, repo_id, user_id, static_dir):
    """
    Import a course from an XBundle object.

    Args:
        bundle (xbundle.XBundle): Course as xbundle XML
        repo_id (int): Primary key of repository course belongs to
        user_id (int): Primary key of Django user doing the import
        static_dir (unicode): location of static files
    Returns:
        learningresources.models.Course
    """
    src = bundle.course
    course = create_course(
        org=src.attrib["org"],
        repo_id=repo_id,
        course_number=src.attrib["course"],
        run=src.attrib["semester"],
        user_id=user_id,
    )
    import_static_assets(course, static_dir)
    import_children(course, src, None, '')
    populate_xanalytics_fields.delay(course.id)
    # This triggers a bulk indexing of all LearningResource instances
    # for the course at once.
    index_resources(
        get_resources(repo_id).filter(course__id=course.id).values_list(
            "id", flat=True))
    return course
Пример #3
0
    def test_list_courses(self):
        """
        Tests the api to list courses in a repo
        """
        res = self.get_courses(repo_slug=self.repo.slug)
        self.assertEqual(res['count'], 1)

        # check content returned
        course_1 = res['results'][0]
        self.assertDictEqual(
            course_1, {
                'org': self.course.org,
                'run': self.course.run,
                'course_number': self.course.course_number,
                'id': self.course.id
            })
        # create another course
        course_params = {
            'org': 'my org',
            'repo_id': self.repo.id,
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }
        second_course = create_course(**course_params)
        res = self.get_courses(repo_slug=self.repo.slug)
        self.assertEqual(res['count'], 2)

        # check the courses are ordered by creation/id
        course_1 = res['results'][0]
        course_2 = res['results'][1]
        self.assertEqual(course_1['id'], self.course.id)
        self.assertEqual(course_2['id'], second_course.id)
        self.assertTrue(course_1['id'] < course_2['id'])
Пример #4
0
def import_course(bundle, repo_id, user_id, static_dir):
    """
    Import a course from an XBundle object.

    Args:
        bundle (xbundle.XBundle): Course as xbundle XML
        repo_id (int): Primary key of repository course belongs to
        user_id (int): Primary key of Django user doing the import
        static_dir (unicode): location of static files
    Returns:
        learningresources.models.Course
    """
    src = bundle.course
    course = create_course(
        org=src.attrib["org"],
        repo_id=repo_id,
        course_number=src.attrib["course"],
        run=src.attrib["semester"],
        user_id=user_id,
    )
    import_static_assets(course, static_dir)
    import_children(course, src, None, '')
    populate_xanalytics_fields.delay(course.id)
    # This triggers a bulk indexing of all LearningResource instances
    # for the course at once.
    index_resources(
        get_resources(repo_id).filter(
            course__id=course.id).values_list("id", flat=True))
    return course
Пример #5
0
def import_course(bundle, repo_id, user_id, static_dir):
    """
    Import a course from an XBundle object.

    Args:
        bundle (xbundle.XBundle): Course as xbundle XML
        repo_id (int): Primary key of repository course belongs to
        user_id (int): Primary key of Django user doing the import
        static_dir (unicode): location of static files
    Returns:
        learningresources.models.Course
    """
    src = bundle.course

    course = create_course(
        org=src.attrib["org"],
        repo_id=repo_id,
        course_number=src.attrib["course"],
        run=src.attrib["semester"],
        user_id=user_id,
    )
    import_static_assets(course, static_dir)
    import_children(course, src, None, '')
    populate_xanalytics_fields.delay(course.id)
    return course
Пример #6
0
    def test_delete_course(self):
        """
        Authorizations for delete a course
        Only user with import permission (admin and curator) can delete a repo
        """
        course_params = {
            'org': 'my org',
            'repo_id': self.repo.id,
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }

        # anonymous user
        self.logout()
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )

        # user not belonging to repo
        self.login(self.user_norepo.username)
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )
        self.logout()

        # author
        self.login(self.author_user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )
        self.logout()

        # curator
        self.login(self.curator_user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id
        )
        self.logout()

        # recreate course
        self.course = create_course(**course_params)

        # administrator
        self.login(self.user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id
        )
Пример #7
0
    def test_delete_course(self):
        """
        Authorizations for delete a course
        Only user with import permission (admin and curator) can delete a repo
        """
        course_params = {
            'org': 'my org',
            'repo_id': self.repo.id,
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }

        # anonymous user
        self.logout()
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )

        # user not belonging to repo
        self.login(self.user_norepo.username)
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )
        self.logout()

        # author
        self.login(self.author_user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id,
            expected_status=403
        )
        self.logout()

        # curator
        self.login(self.curator_user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id
        )
        self.logout()

        # recreate course
        self.course = create_course(**course_params)

        # administrator
        self.login(self.user.username)
        self.delete_course(
            self.repo.slug,
            self.course.id
        )
Пример #8
0
    def test_create(self):
        """
        Create a course.
        """
        before = course_count()
        course = api.create_course(**self.kwargs)
        after = course_count()
        self.assertTrue(after == before + 1)
        self.assertTrue(course is not None)

        # Can't create a duplicate.
        with self.assertRaises(ValueError):
            api.create_course(**self.kwargs)
        self.assertTrue(course_count() == after)

        # NOT NULL constraint fails on org
        with self.assertRaises(IntegrityError) as ex:
            api.create_course(None, self.repo.id, "course", "run", self.user.id)

        self.assertIn("org", ex.exception.args[0])
Пример #9
0
    def test_create(self):
        """
        Create a course.
        """
        before = course_count()
        course = api.create_course(**self.kwargs)
        after = course_count()
        self.assertTrue(after == before + 1)
        self.assertTrue(course is not None)

        # Can't create a duplicate.
        with self.assertRaises(ValueError):
            api.create_course(**self.kwargs)
        self.assertTrue(course_count() == after)

        # NOT NULL constraint fails on org
        with self.assertRaises(IntegrityError) as ex:
            api.create_course(
                None, self.repo.id, "course", "run", self.user.id)

        self.assertIn("org", ex.exception.args[0])
Пример #10
0
def import_course(bundle, repo_id, user_id):
    """
    Import a course from an XBundle object.

    Args:
        bundle (xbundle.XBundle): Course as xbundle XML
        user_id (int): pk of Django user doing the import
    """
    src = bundle.course
    course = create_course(
        org=src.attrib["org"],
        repo_id=repo_id,
        course_number=src.attrib["course"],
        run=src.attrib["semester"],
        user_id=user_id,
    )
    import_children(course, src, None)
Пример #11
0
Файл: base.py Проект: jetej/lore
    def setUp(self):
        """set up"""
        super(LoreTestCase, self).setUp()
        self.user = User.objects.create_user(
            username=self.USERNAME, password=self.PASSWORD
        )
        add_repo_perm = Permission.objects.get(codename=self.ADD_REPO_PERM)
        self.user.user_permissions.add(add_repo_perm)
        # user without permission to add a repo
        self.user_norepo = User.objects.create_user(
            username=self.USERNAME_NO_REPO, password=self.PASSWORD
        )

        self.repo = create_repo(
            name="test repo",
            description="just a test",
            user_id=self.user.id,
        )
        self.course = create_course(
            org="test-org",
            repo_id=self.repo.id,
            course_number="infinity",
            run="Febtober",
            user_id=self.user.id,
        )
        self.resource = self.create_resource(
            course=self.course,
            parent=None,
            resource_type="example",
            title="silly example",
            content_xml="<blah>blah</blah>",
            mpath="/blah",
            url_name="url_name1",
        )

        assign_user_to_repo_group(
            self.user,
            self.repo,
            GroupTypes.REPO_ADMINISTRATOR
        )
        self.toy_resource_count = 18  # Resources in toy course.
        self.toy_asset_count = 5  # Static assets in toy course.
        self.client = Client()

        self.login(username=self.USERNAME)
Пример #12
0
    def setUp(self):
        """set up"""
        super(LoreTestCase, self).setUp()
        recreate_index()
        self.user = User.objects.create_user(username=self.USERNAME,
                                             password=self.PASSWORD)
        add_repo_perm = Permission.objects.get(codename=self.ADD_REPO_PERM)
        self.user.user_permissions.add(add_repo_perm)
        # user without permission to add a repo
        self.user_norepo = User.objects.create_user(
            username=self.USERNAME_NO_REPO, password=self.PASSWORD)

        self.repo = create_repo(
            name="test repo",
            description="just a test",
            user_id=self.user.id,
        )
        self.course = create_course(
            org="test-org",
            repo_id=self.repo.id,
            course_number="infinity",
            run="Febtober",
            user_id=self.user.id,
        )
        self.resource = self.create_resource(
            course=self.course,
            parent=None,
            resource_type="example",
            title="silly example",
            content_xml="<blah>blah</blah>",
            mpath="/blah",
            url_name="url_name1",
        )

        self.toy_resource_count = 18  # Resources in toy course.
        self.toy_asset_count = 5  # Static assets in toy course.
        self.client = Client()

        self.login(username=self.USERNAME)
        refresh_index()
Пример #13
0
    def test_list_courses(self):
        """
        Tests the api to list courses in a repo
        """
        res = self.get_courses(repo_slug=self.repo.slug)
        self.assertEqual(res['count'], 1)

        # check content returned
        course_1 = res['results'][0]
        self.assertDictEqual(
            course_1,
            {
                'org': self.course.org,
                'run': self.course.run,
                'course_number': self.course.course_number,
                'id': self.course.id
            }
        )
        # create another course
        course_params = {
            'org': 'my org',
            'repo_id': self.repo.id,
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }
        second_course = create_course(**course_params)
        res = self.get_courses(repo_slug=self.repo.slug)
        self.assertEqual(res['count'], 2)

        # check the courses are ordered by creation/id
        course_1 = res['results'][0]
        course_2 = res['results'][1]
        self.assertEqual(course_1['id'], self.course.id)
        self.assertEqual(course_2['id'], second_course.id)
        self.assertTrue(course_1['id'] < course_2['id'])
Пример #14
0
    def test_delete_course(self):
        """
        REST tests to delete a Course.
        All learning resources and static assets connected to the course are
        deleted as well.
        Other courses, learning resources types, terms, vocabularies,
        repositories are not deleted.
        Note: learning resources types are created during the import of the
        course but they are related to the repository.
        """
        # trying to delete non existing courses
        self.delete_course(
            repo_slug=self.repo.slug,
            course_id='foo',
            expected_status=404
        )
        self.delete_course(
            repo_slug=self.repo.slug,
            course_id=1234567,
            expected_status=404
        )

        # environment before importing a course
        self.count_resources(
            repositories=1,
            courses=1,
            learning_resources=1,
            learning_resource_types=1
        )

        # Import the course tarball
        self.import_course_tarball(self.repo)
        # create a vocabulary and term
        vocabulary = self.create_vocabulary(self.repo.slug)
        self.create_term(self.repo.slug, vocabulary['slug'])

        # environment before deleting the course
        self.count_resources(
            repositories=1,
            courses=2,
            learning_resources=19,
            learning_resource_types=8,
            static_assetts=5,
            terms=1,
            vocabularies=1
        )

        # make sure of the course that is going to be deleted
        courses = Course.objects.all()
        self.assertEqual(courses[0].id, self.course.id)
        self.assertNotEqual(courses[1].id, self.course.id)

        # try to get the right course but non existing repo
        self.delete_course(
            repo_slug='nonsense',
            course_id=courses[1].id,
            expected_status=404
        )

        # delete the course
        self.delete_course(self.repo.slug, courses[1].id)

        # environment after deleting the course
        self.count_resources(
            repositories=1,
            courses=1,
            learning_resources=1,
            learning_resource_types=8,
            terms=1,
            vocabularies=1
        )

        # the course remaining is the one not deleted
        courses = Course.objects.all()
        self.assertEqual(courses[0].id, self.course.id)

        # and the learning resources remaining are associated with
        # the remaining course
        for learning_resource in LearningResource.objects.all():
            self.assertEqual(
                learning_resource.course.id,
                self.course.id
            )

        # try to delete the remaining course but with the wrong repo
        # create another repo
        another_repo_dict = {
            'name': 'another_repo_name',
            'description': 'description',
        }
        repo_res = self.create_repository(another_repo_dict)
        # and another course in it
        course_params = {
            'org': 'my org',
            'repo_id': repo_res['id'],
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }
        second_course = create_course(**course_params)

        # try to get the right course but on wrong repo
        self.delete_course(
            repo_slug=repo_res['slug'],
            course_id=self.course.id,
            expected_status=404
        )
        # again with repo and course swapped
        self.delete_course(
            repo_slug=self.repo.slug,
            course_id=second_course.id,
            expected_status=404
        )
Пример #15
0
    def test_delete_course(self):
        """
        REST tests to delete a Course.
        All learning resources and static assets connected to the course are
        deleted as well.
        Other courses, learning resources types, terms, vocabularies,
        repositories are not deleted.
        Note: learning resources types are created during the import of the
        course but they are related to the repository.
        """
        # trying to delete non existing courses
        self.delete_course(repo_slug=self.repo.slug,
                           course_id='foo',
                           expected_status=404)
        self.delete_course(repo_slug=self.repo.slug,
                           course_id=1234567,
                           expected_status=404)

        # environment before importing a course
        self.count_resources(repositories=1,
                             courses=1,
                             learning_resources=1,
                             learning_resource_types=1)

        # Import the course tarball
        self.import_course_tarball(self.repo)
        # create a vocabulary and term
        vocabulary = self.create_vocabulary(self.repo.slug)
        self.create_term(self.repo.slug, vocabulary['slug'])

        # environment before deleting the course
        self.count_resources(repositories=1,
                             courses=2,
                             learning_resources=19,
                             learning_resource_types=8,
                             static_assetts=5,
                             terms=1,
                             vocabularies=1)

        # make sure of the course that is going to be deleted
        courses = Course.objects.all()
        self.assertEqual(courses[0].id, self.course.id)
        self.assertNotEqual(courses[1].id, self.course.id)

        # try to get the right course but non existing repo
        self.delete_course(repo_slug='nonsense',
                           course_id=courses[1].id,
                           expected_status=404)

        # delete the course
        self.delete_course(self.repo.slug, courses[1].id)

        # environment after deleting the course
        self.count_resources(repositories=1,
                             courses=1,
                             learning_resources=1,
                             learning_resource_types=8,
                             terms=1,
                             vocabularies=1)

        # the course remaining is the one not deleted
        courses = Course.objects.all()
        self.assertEqual(courses[0].id, self.course.id)

        # and the learning resources remaining are associated with
        # the remaining course
        for learning_resource in LearningResource.objects.all():
            self.assertEqual(learning_resource.course.id, self.course.id)

        # try to delete the remaining course but with the wrong repo
        # create another repo
        another_repo_dict = {
            'name': 'another_repo_name',
            'description': 'description',
        }
        repo_res = self.create_repository(another_repo_dict)
        # and another course in it
        course_params = {
            'org': 'my org',
            'repo_id': repo_res['id'],
            'course_number': 'second course number',
            'run': "second course run",
            'user_id': self.user.id
        }
        second_course = create_course(**course_params)

        # try to get the right course but on wrong repo
        self.delete_course(repo_slug=repo_res['slug'],
                           course_id=self.course.id,
                           expected_status=404)
        # again with repo and course swapped
        self.delete_course(repo_slug=self.repo.slug,
                           course_id=second_course.id,
                           expected_status=404)
Пример #16
0
    def test_duplicate(self):
        """
        Test that exporting resources with same file path
        is reported and handled correctly.
        """

        with TemporaryFile() as temp1:
            with TemporaryFile() as temp2:
                temp1.write(b"first")
                temp2.write(b"second")

                # Create two static assets with the same name but different
                # paths so no renaming is done on storage side.
                static_filename = "iamafile.txt"
                static_path1 = os.path.join(
                    STATIC_ASSET_BASEPATH.format(
                        org=self.resource.course.org,
                        course_number=self.resource.course.course_number,
                        run=self.resource.course.run,
                    ),
                    static_filename
                )

                file1 = File(temp1, name=static_filename)
                file2 = File(temp2, name=static_filename)

                default_storage.delete(static_path1)
                asset1 = create_static_asset(self.resource.course.id, file1)
                self.resource.static_assets.add(asset1)

                course2 = create_course(
                    "org2", self.repo.id, self.resource.course.course_number,
                    self.resource.course.run, self.user.id
                )
                resource2 = create_resource(
                    course=course2,
                    parent=None,
                    resource_type=self.resource.learning_resource_type.name,
                    title=self.resource.title,
                    dpath="",
                    mpath="",
                    content_xml="",
                    url_name=self.resource.url_name
                )
                static_path2 = os.path.join(
                    STATIC_ASSET_BASEPATH.format(
                        org=course2.org,
                        course_number=course2.course_number,
                        run=course2.run,
                    ),
                    static_filename
                )
                default_storage.delete(static_path2)
                asset2 = create_static_asset(resource2.course.id, file2)
                resource2.static_assets.add(asset2)

                # Export the resources. The second static asset should have
                # the number _1 attached to it.
                try:

                    resources = [self.resource, resource2]
                    tempdir, collision = export_resources_to_directory(
                        resources)
                    try:
                        self.assertTrue(collision)
                        assert_resource_directory(self, resources, tempdir)
                    finally:
                        rmtree(tempdir)
                finally:
                    default_storage.delete(asset1.asset.name)
                    default_storage.delete(asset2.asset.name)
Пример #17
0
    def test_duplicate(self):
        """
        Test that exporting resources with same file path
        is reported and handled correctly.
        """

        with TemporaryFile() as temp1:
            with TemporaryFile() as temp2:
                temp1.write(b"first")
                temp2.write(b"second")

                # Create two static assets with the same name but different
                # paths so no renaming is done on storage side.
                static_filename = "iamafile.txt"
                static_path1 = os.path.join(
                    STATIC_ASSET_BASEPATH.format(
                        org=self.resource.course.org,
                        course_number=self.resource.course.course_number,
                        run=self.resource.course.run,
                    ), static_filename)

                file1 = File(temp1, name=static_filename)
                file2 = File(temp2, name=static_filename)

                default_storage.delete(static_path1)
                asset1 = create_static_asset(self.resource.course.id, file1)
                self.resource.static_assets.add(asset1)

                course2 = create_course("org2", self.repo.id,
                                        self.resource.course.course_number,
                                        self.resource.course.run, self.user.id)
                resource2 = create_resource(
                    course=course2,
                    parent=None,
                    resource_type=self.resource.learning_resource_type.name,
                    title=self.resource.title,
                    dpath="",
                    mpath="",
                    content_xml="",
                    url_name=self.resource.url_name)
                static_path2 = os.path.join(
                    STATIC_ASSET_BASEPATH.format(
                        org=course2.org,
                        course_number=course2.course_number,
                        run=course2.run,
                    ), static_filename)
                default_storage.delete(static_path2)
                asset2 = create_static_asset(resource2.course.id, file2)
                resource2.static_assets.add(asset2)

                # Export the resources. The second static asset should have
                # the number _1 attached to it.
                try:

                    resources = [self.resource, resource2]
                    tempdir, collision = export_resources_to_directory(
                        resources)
                    try:
                        self.assertTrue(collision)
                        assert_resource_directory(self, resources, tempdir)
                    finally:
                        rmtree(tempdir)
                finally:
                    default_storage.delete(asset1.asset.name)
                    default_storage.delete(asset2.asset.name)