Exemple #1
0
    def post(self, request):
        """Handle all actions from courses view"""

        if not request.user.is_staff:
            raise Http404

        action = request.POST.get('action', '')
        track.views.server_track(request, action, {},
                                 page='courses_sysdashboard')

        courses = {course.id: course for course in self.get_courses()}
        if action == 'add_course':
            gitloc = request.POST.get('repo_location', '').strip().replace(' ', '').replace(';', '')
            branch = request.POST.get('repo_branch', '').strip().replace(' ', '').replace(';', '')
            self.msg += self.get_course_from_git(gitloc, branch)

        elif action == 'del_course':
            course_id = request.POST.get('course_id', '').strip()
            course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
            course_found = False
            if course_key in courses:
                course_found = True
                course = courses[course_key]
            else:
                try:
                    course = get_course_by_id(course_key)
                    course_found = True
                except Exception, err:   # pylint: disable=broad-except
                    self.msg += _(
                        'Error - cannot get course with ID {0}<br/><pre>{1}</pre>'
                    ).format(
                        course_key,
                        escape(str(err))
                    )

            is_xml_course = (modulestore().get_modulestore_type(course_key) == XML_MODULESTORE_TYPE)
            if course_found and is_xml_course:
                cdir = course.data_dir
                self.def_ms.courses.pop(cdir)

                # now move the directory (don't actually delete it)
                new_dir = "{course_dir}_deleted_{timestamp}".format(
                    course_dir=cdir,
                    timestamp=int(time.time())
                )
                os.rename(settings.DATA_DIR / cdir, settings.DATA_DIR / new_dir)

                self.msg += (u"<font color='red'>Deleted "
                             u"{0} = {1} ({2})</font>".format(
                                 cdir, course.id, course.display_name))

            elif course_found and not is_xml_course:
                # delete course that is stored with mongodb backend
                content_store = contentstore()
                commit = True
                delete_course(self.def_ms, content_store, course.id, commit)
                # don't delete user permission groups, though
                self.msg += \
                    u"<font color='red'>{0} {1} = {2} ({3})</font>".format(
                        _('Deleted'), course.location.to_deprecated_string(), course.id.to_deprecated_string(), course.display_name)
    def test_delete_course(self):
        module_store = modulestore("direct")
        import_from_xml(module_store, "common/test/data/", ["full"])

        content_store = contentstore()

        location = CourseDescriptor.id_to_location("edX/full/6.002_Spring_2012")

        delete_course(module_store, content_store, location, commit=True)

        items = module_store.get_items(Location(["i4x", "edX", "full", "vertical", None]))
        self.assertEqual(len(items), 0)
Exemple #3
0
    def test_delete_course(self):
        module_store = modulestore('direct')
        import_from_xml(module_store, 'common/test/data/', ['full'])

        content_store = contentstore()

        location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')

        delete_course(module_store, content_store, location, commit=True)

        items = module_store.get_items(Location(['i4x', 'edX', 'full', 'vertical', None]))
        self.assertEqual(len(items), 0)
Exemple #4
0
    def post(self, request):
        """Handle all actions from courses view"""

        if not request.user.is_staff:
            raise Http404

        action = request.POST.get("action", "")
        track.views.server_track(request, action, {}, page="courses_sysdashboard")

        courses = self.get_courses()
        if action == "add_course":
            gitloc = request.POST.get("repo_location", "").strip().replace(" ", "").replace(";", "")
            branch = request.POST.get("repo_branch", "").strip().replace(" ", "").replace(";", "")
            self.msg += self.get_course_from_git(gitloc, branch)

        elif action == "del_course":
            course_id = request.POST.get("course_id", "").strip()
            course_found = False
            if course_id in courses:
                course_found = True
                course = courses[course_id]
            else:
                try:
                    course = get_course_by_id(course_id)
                    course_found = True
                except Exception, err:  # pylint: disable=broad-except
                    self.msg += _("Error - cannot get course with ID " "{0}<br/><pre>{1}</pre>").format(
                        course_id, escape(str(err))
                    )

            is_xml_course = modulestore().get_modulestore_type(course_id) == XML_MODULESTORE_TYPE
            if course_found and is_xml_course:
                cdir = course.data_dir
                self.def_ms.courses.pop(cdir)

                # now move the directory (don't actually delete it)
                new_dir = "{course_dir}_deleted_{timestamp}".format(course_dir=cdir, timestamp=int(time.time()))
                os.rename(settings.DATA_DIR / cdir, settings.DATA_DIR / new_dir)

                self.msg += u"<font color='red'>Deleted " u"{0} = {1} ({2})</font>".format(
                    cdir, course.id, course.display_name
                )

            elif course_found and not is_xml_course:
                # delete course that is stored with mongodb backend
                loc = course.location
                content_store = contentstore()
                commit = True
                delete_course(self.def_ms, content_store, loc, commit)
                # don't delete user permission groups, though
                self.msg += u"<font color='red'>{0} {1} = {2} ({3})</font>".format(
                    _("Deleted"), loc, course.id, course.display_name
                )
Exemple #5
0
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError(
                "delete_course requires one or more arguments: <location> |commit|"
            )

        loc_str = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        if query_yes_no("Deleting course {0}. Confirm?".format(loc_str),
                        default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!",
                            default="no"):
                loc = CourseDescriptor.id_to_location(loc_str)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user permissions groups associated with this course
                    if commit:
                        _delete_course_group(loc)
Exemple #6
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

    course_id_dict = Location.parse_course_id(course_id)
    module_store.ignore_write_events_on_courses.append(
        '{org}/{course}'.format(**course_id_dict))

    loc = CourseDescriptor.id_to_location(course_id)
    if delete_course(module_store, content_store, loc, commit):

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
                staff_role = CourseStaffRole(loc)
                staff_role.remove_users(*staff_role.users_with_role())
                instructor_role = CourseInstructorRole(loc)
                instructor_role.remove_users(
                    *instructor_role.users_with_role())
            except Exception as err:
                log.error(
                    "Error in deleting course groups for {0}: {1}".format(
                        loc, err))

            # remove location of this course from loc_mapper and cache
            loc_mapper().delete_course_mapping(loc)
Exemple #7
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

    org, course_num, _ = course_id.split("/")
    module_store.ignore_write_events_on_courses.append('{0}/{1}'.format(
        org, course_num))

    loc = CourseDescriptor.id_to_location(course_id)
    if delete_course(module_store, content_store, loc, commit):
        print 'removing forums permissions and roles...'
        unseed_permissions_roles(course_id)

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
                staff_role = CourseStaffRole(loc)
                staff_role.remove_users(*staff_role.users_with_role())
                instructor_role = CourseInstructorRole(loc)
                instructor_role.remove_users(
                    *instructor_role.users_with_role())
            except Exception as err:
                log.error(
                    "Error in deleting course groups for {0}: {1}".format(
                        loc, err))
Exemple #8
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

    course_id_dict = Location.parse_course_id(course_id)
    module_store.ignore_write_events_on_courses.append('{org}/{course}'.format(**course_id_dict))

    loc = CourseDescriptor.id_to_location(course_id)
    if delete_course(module_store, content_store, loc, commit):

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
                staff_role = CourseStaffRole(loc)
                staff_role.remove_users(*staff_role.users_with_role())
                instructor_role = CourseInstructorRole(loc)
                instructor_role.remove_users(*instructor_role.users_with_role())
            except Exception as err:
                log.error("Error in deleting course groups for {0}: {1}".format(loc, err))

            # remove location of this course from loc_mapper and cache
            loc_mapper().delete_course_mapping(loc)
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError(
                "delete_course requires one or more arguments: <location> |commit|")

        loc_str = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        if query_yes_no("Deleting course {0}. Confirm?".format(loc_str), default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
                loc = CourseDescriptor.id_to_location(loc_str)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user
                    # permissions groups associated with this course
                    if commit:
                        _delete_course_group(loc)
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError("delete_course requires one or more arguments: <location> |commit|")

        course_id = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        org, course_num, run = course_id.split("/")
        ms.ignore_write_events_on_courses.append('{0}/{1}'.format(org, course_num))

        if query_yes_no("Deleting course {0}. Confirm?".format(course_id), default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
                loc = CourseDescriptor.id_to_location(course_id)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user permissions groups associated with this course
                    if commit:
                        try:
                            _delete_course_group(loc)
                        except Exception as err:
                            print("Error in deleting course groups for {0}: {1}".format(loc, err))
Exemple #11
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

    org, course_num, _ = course_id.split("/")
    module_store.ignore_write_events_on_courses.append('{0}/{1}'.format(
        org, course_num))

    loc = CourseDescriptor.id_to_location(course_id)
    if delete_course(module_store, content_store, loc, commit):
        print 'removing forums permissions and roles...'
        unseed_permissions_roles(course_id)

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
                staff_role = CourseStaffRole(loc)
                staff_role.remove_users(*staff_role.users_with_role())
                instructor_role = CourseInstructorRole(loc)
                instructor_role.remove_users(
                    *instructor_role.users_with_role())
            except Exception as err:
                log.error(
                    "Error in deleting course groups for {0}: {1}".format(
                        loc, err))
Exemple #12
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

    module_store.ignore_write_events_on_courses.add(course_id)

    if delete_course(module_store, content_store, course_id, commit):

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
                staff_role = CourseStaffRole(course_id)
                staff_role.remove_users(*staff_role.users_with_role())
                instructor_role = CourseInstructorRole(course_id)
                instructor_role.remove_users(
                    *instructor_role.users_with_role())
            except Exception as err:
                log.error(
                    "Error in deleting course groups for {0}: {1}".format(
                        course_id, err))
    def test_branching(self):
        """
        Exercise branching code of import
        """
        repo_dir = self.GIT_REPO_DIR
        # Test successful import from command
        if not os.path.isdir(repo_dir):
            os.mkdir(repo_dir)
        self.addCleanup(shutil.rmtree, repo_dir)

        # Checkout non existent branch
        with self.assertRaisesRegexp(GitImportError, GitImportError.REMOTE_BRANCH_MISSING):
            git_import.add_repo(self.TEST_REPO, repo_dir / 'edx4edx_lite', 'asdfasdfasdf')

        # Checkout new branch
        git_import.add_repo(self.TEST_REPO,
                            repo_dir / 'edx4edx_lite',
                            self.TEST_BRANCH)
        def_ms = modulestore()
        # Validate that it is different than master
        self.assertIsNotNone(def_ms.get_course(self.TEST_BRANCH_COURSE))

        # Attempt to check out the same branch again to validate branch choosing
        # works
        git_import.add_repo(self.TEST_REPO,
                            repo_dir / 'edx4edx_lite',
                            self.TEST_BRANCH)

        # Delete to test branching back to master
        delete_course(def_ms, contentstore(),
                      def_ms.get_course(self.TEST_BRANCH_COURSE).location,
                      True)
        self.assertIsNone(def_ms.get_course(self.TEST_BRANCH_COURSE))
        git_import.add_repo(self.TEST_REPO,
                            repo_dir / 'edx4edx_lite',
                            'master')
        self.assertIsNone(def_ms.get_course(self.TEST_BRANCH_COURSE))
        self.assertIsNotNone(def_ms.get_course(self.TEST_COURSE))
    def test_branching(self):
        """
        Exercise branching code of import
        """
        repo_dir = self.GIT_REPO_DIR
        # Test successful import from command
        if not os.path.isdir(repo_dir):
            os.mkdir(repo_dir)
        self.addCleanup(shutil.rmtree, repo_dir)

        # Checkout non existent branch
        with self.assertRaisesRegexp(GitImportError,
                                     GitImportError.REMOTE_BRANCH_MISSING):
            git_import.add_repo(self.TEST_REPO, repo_dir / 'edx4edx_lite',
                                'asdfasdfasdf')

        # Checkout new branch
        git_import.add_repo(self.TEST_REPO, repo_dir / 'edx4edx_lite',
                            self.TEST_BRANCH)
        def_ms = modulestore()
        # Validate that it is different than master
        self.assertIsNotNone(def_ms.get_course(self.TEST_BRANCH_COURSE))

        # Attempt to check out the same branch again to validate branch choosing
        # works
        git_import.add_repo(self.TEST_REPO, repo_dir / 'edx4edx_lite',
                            self.TEST_BRANCH)

        # Delete to test branching back to master
        delete_course(def_ms, contentstore(), self.TEST_BRANCH_COURSE, True)
        self.assertIsNone(def_ms.get_course(self.TEST_BRANCH_COURSE))
        git_import.add_repo(self.TEST_REPO, repo_dir / 'edx4edx_lite',
                            'master')
        self.assertIsNone(def_ms.get_course(self.TEST_BRANCH_COURSE))
        self.assertIsNotNone(
            def_ms.get_course(
                SlashSeparatedCourseKey.from_deprecated_string(
                    self.TEST_COURSE)))
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError(
                "delete_course requires one or more arguments: <location> |commit|"
            )

        course_id = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        ms.set_modulestore_configuration({
            'metadata_inheritance_cache_subsystem':
            CACHE,
            'request_cache':
            RequestCache.get_request_cache()
        })

        org, course_num, run = course_id.split("/")
        ms.ignore_write_events_on_courses.append('{0}/{1}'.format(
            org, course_num))

        if query_yes_no("Deleting course {0}. Confirm?".format(course_id),
                        default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!",
                            default="no"):
                loc = CourseDescriptor.id_to_location(course_id)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user permissions groups associated with this course
                    if commit:
                        try:
                            _delete_course_group(loc)
                        except Exception as err:
                            print(
                                "Error in deleting course groups for {0}: {1}".
                                format(loc, err))
Exemple #16
0
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore()
    content_store = contentstore()

    with store_bulk_write_operations_on_course(module_store, course_id):
        if delete_course(module_store, content_store, course_id, commit):

            print 'removing User permissions from course....'
            # in the django layer, we need to remove all the user permissions groups associated with this course
            if commit:
                try:
                    staff_role = CourseStaffRole(course_id)
                    staff_role.remove_users(*staff_role.users_with_role())
                    instructor_role = CourseInstructorRole(course_id)
                    instructor_role.remove_users(*instructor_role.users_with_role())
                except Exception as err:
                    log.error("Error in deleting course groups for {0}: {1}".format(course_id, err))
Exemple #17
0
    def test_export_course(self):
        module_store = modulestore('direct')
        draft_store = modulestore('draft')
        content_store = contentstore()

        import_from_xml(module_store, 'common/test/data/', ['full'])
        location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')

        # get a vertical (and components in it) to put into 'draft'
        vertical = module_store.get_item(Location(['i4x', 'edX', 'full',
                                         'vertical', 'vertical_66', None]), depth=1)

        draft_store.clone_item(vertical.location, vertical.location)

        # We had a bug where orphaned draft nodes caused export to fail. This is here to cover that case.
        draft_store.clone_item(vertical.location, Location(['i4x', 'edX', 'full',
                                                            'vertical', 'no_references', 'draft']))

        for child in vertical.get_children():
            draft_store.clone_item(child.location, child.location)

        root_dir = path(mkdtemp_clean())

        # now create a private vertical
        private_vertical = draft_store.clone_item(vertical.location,
                                                  Location(['i4x', 'edX', 'full', 'vertical', 'a_private_vertical', None]))

        # add private to list of children
        sequential = module_store.get_item(Location(['i4x', 'edX', 'full',
                                           'sequential', 'Administrivia_and_Circuit_Elements', None]))
        private_location_no_draft = private_vertical.location.replace(revision=None)
        module_store.update_children(sequential.location, sequential.children +
                                     [private_location_no_draft.url()])

        # read back the sequential, to make sure we have a pointer to
        sequential = module_store.get_item(Location(['i4x', 'edX', 'full',
                                                     'sequential', 'Administrivia_and_Circuit_Elements', None]))

        self.assertIn(private_location_no_draft.url(), sequential.children)

        print 'Exporting to tempdir = {0}'.format(root_dir)

        # export out to a tempdir
        export_to_xml(module_store, content_store, location, root_dir, 'test_export', draft_modulestore=draft_store)

        # check for static tabs
        self.verify_content_existence(module_store, root_dir, location, 'tabs', 'static_tab', '.html')

        # check for custom_tags
        self.verify_content_existence(module_store, root_dir, location, 'info', 'course_info', '.html')

        # check for custom_tags
        self.verify_content_existence(module_store, root_dir, location, 'custom_tags', 'custom_tag_template')

        # check for about content
        self.verify_content_existence(module_store, root_dir, location, 'about', 'about', '.html')

        # check for graiding_policy.json
        filesystem = OSFS(root_dir / 'test_export/policies/6.002_Spring_2012')
        self.assertTrue(filesystem.exists('grading_policy.json'))

        course = module_store.get_item(location)
        # compare what's on disk compared to what we have in our course
        with filesystem.open('grading_policy.json', 'r') as grading_policy:
            on_disk = loads(grading_policy.read())
            self.assertEqual(on_disk, course.grading_policy)

        #check for policy.json
        self.assertTrue(filesystem.exists('policy.json'))

        # compare what's on disk to what we have in the course module
        with filesystem.open('policy.json', 'r') as course_policy:
            on_disk = loads(course_policy.read())
            self.assertIn('course/6.002_Spring_2012', on_disk)
            self.assertEqual(on_disk['course/6.002_Spring_2012'], own_metadata(course))

        # remove old course
        delete_course(module_store, content_store, location)

        # reimport
        import_from_xml(module_store, root_dir, ['test_export'], draft_store=draft_store)

        items = module_store.get_items(Location(['i4x', 'edX', 'full', 'vertical', None]))
        self.assertGreater(len(items), 0)
        for descriptor in items:
            # don't try to look at private verticals. Right now we're running
            # the service in non-draft aware
            if getattr(descriptor, 'is_draft', False):
                print "Checking {0}....".format(descriptor.location.url())
                resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()}))
                self.assertEqual(resp.status_code, 200)

        # verify that we have the content in the draft store as well
        vertical = draft_store.get_item(Location(['i4x', 'edX', 'full',
                                                  'vertical', 'vertical_66', None]), depth=1)

        self.assertTrue(getattr(vertical, 'is_draft', False))
        for child in vertical.get_children():
            self.assertTrue(getattr(child, 'is_draft', False))

        # make sure that we don't have a sequential that is in draft mode
        sequential = draft_store.get_item(Location(['i4x', 'edX', 'full',
                                                    'sequential', 'Administrivia_and_Circuit_Elements', None]))

        self.assertFalse(getattr(sequential, 'is_draft', False))

        # verify that we have the private vertical
        test_private_vertical = draft_store.get_item(Location(['i4x', 'edX', 'full',
                                                               'vertical', 'vertical_66', None]))

        self.assertTrue(getattr(test_private_vertical, 'is_draft', False))

        # make sure the textbook survived the export/import
        course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))

        self.assertGreater(len(course.textbooks), 0)

        shutil.rmtree(root_dir)