Пример #1
0
    def test_course_constructor_bad_package_id(self, bad_id):
        """
        Test all sorts of badly-formed package_ids (and urls with those package_ids)
        """
        with self.assertRaises(InvalidKeyError):
            CourseLocator(org=bad_id, offering='test')

        with self.assertRaises(InvalidKeyError):
            CourseLocator(org='test', offering=bad_id)

        with self.assertRaises(InvalidKeyError):
            CourseKey.from_string('course-locator:test+{}'.format(bad_id))
Пример #2
0
def course_handler(request, course_key_string=None):
    """
    The restful handler for course specific requests.
    It provides the course tree with the necessary information for identifying and labeling the parts. The root
    will typically be a 'course' object but may not be especially as we support modules.

    GET
        html: return course listing page if not given a course id
        html: return html page overview for the given course if given a course id
        json: return json representing the course branch's index entry as well as dag w/ all of the children
        replaced w/ json docs where each doc has {'_id': , 'display_name': , 'children': }
    POST
        json: create a course, return resulting json
        descriptor (same as in GET course/...). Leaving off /branch/draft would imply create the course w/ default
        branches. Cannot change the structure contents ('_id', 'display_name', 'children') but can change the
        index entry.
    PUT
        json: update this course (index entry not xblock) such as repointing head, changing display name, org,
        offering. Return same json as above.
    DELETE
        json: delete this branch from this course (leaving off /branch/draft would imply delete the course)
    """
    response_format = request.REQUEST.get('format', 'html')
    if response_format == 'json' or 'application/json' in request.META.get(
            'HTTP_ACCEPT', 'application/json'):
        if request.method == 'GET':
            return JsonResponse(
                _course_json(request,
                             CourseKey.from_string(course_key_string)))
        elif request.method == 'POST':  # not sure if this is only post. If one will have ids, it goes after access
            return create_new_course(request)
        elif not has_course_access(request.user,
                                   CourseKey.from_string(course_key_string)):
            raise PermissionDenied()
        elif request.method == 'PUT':
            raise NotImplementedError()
        elif request.method == 'DELETE':
            raise NotImplementedError()
        else:
            return HttpResponseBadRequest()
    elif request.method == 'GET':  # assume html
        if course_key_string is None:
            return course_listing(request)
        else:
            return course_index(request,
                                CourseKey.from_string(course_key_string))
    else:
        return HttpResponseNotFound()
Пример #3
0
    def clean_course_id(self):
        """Validate the course id"""
        cleaned_id = self.cleaned_data["course_id"]
        try:
            course_key = CourseKey.from_string(cleaned_id)
        except InvalidKeyError:
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(cleaned_id)
            except InvalidKeyError:
                msg = u'Course id invalid.' 
                msg += u' --- Entered course id was: "{0}". '.format(cleaned_id)
                msg += 'Please recheck that you have supplied a valid course id.'
                raise forms.ValidationError(msg)

        if not modulestore().has_course(course_key):
            msg = u'COURSE NOT FOUND'
            msg += u' --- Entered course id was: "{0}". '.format(course_key.to_deprecated_string())
            msg += 'Please recheck that you have supplied a valid course id.'
            raise forms.ValidationError(msg)

        # Now, try and discern if it is a Studio course - HTML editor doesn't work with XML courses
        is_studio_course = modulestore().get_modulestore_type(course_key) != XML_MODULESTORE_TYPE
        if not is_studio_course:
            msg = "Course Email feature is only available for courses authored in Studio. "
            msg += '"{0}" appears to be an XML backed course.'.format(course_key.to_deprecated_string())
            raise forms.ValidationError(msg)

        return course_key
Пример #4
0
    def clean_course_id(self):
        """Validate the course id"""
        cleaned_id = self.cleaned_data["course_id"]
        try:
            course_key = CourseKey.from_string(cleaned_id)
        except InvalidKeyError:
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(
                    cleaned_id)
            except InvalidKeyError:
                msg = u'Course id invalid.'
                msg += u' --- Entered course id was: "{0}". '.format(
                    cleaned_id)
                msg += 'Please recheck that you have supplied a valid course id.'
                raise forms.ValidationError(msg)

        if not modulestore().has_course(course_key):
            msg = u'COURSE NOT FOUND'
            msg += u' --- Entered course id was: "{0}". '.format(
                course_key.to_deprecated_string())
            msg += 'Please recheck that you have supplied a valid course id.'
            raise forms.ValidationError(msg)

        # Now, try and discern if it is a Studio course - HTML editor doesn't work with XML courses
        is_studio_course = modulestore().get_modulestore_type(
            course_key) != XML_MODULESTORE_TYPE
        if not is_studio_course:
            msg = "Course Email feature is only available for courses authored in Studio. "
            msg += '"{0}" appears to be an XML backed course.'.format(
                course_key.to_deprecated_string())
            raise forms.ValidationError(msg)

        return course_key
Пример #5
0
def export_git(request, course_key_string):
    """
    This method serves up the 'Export to Git' page
    """
    course_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    course_module = modulestore().get_course(course_key)
    failed = False

    log.debug('export_git course_module=%s', course_module)

    msg = ""
    if 'action' in request.GET and course_module.giturl:
        if request.GET['action'] == 'push':
            try:
                git_export_utils.export_to_git(
                    course_module.id,
                    course_module.giturl,
                    request.user,
                )
                msg = _('Course successfully exported to git repository')
            except git_export_utils.GitExportError as ex:
                failed = True
                msg = unicode(ex)

    return render_to_response('export_git.html', {
        'context_course': course_module,
        'msg': msg,
        'failed': failed,
    })
Пример #6
0
def orphan_handler(request, course_key_string):
    """
    View for handling orphan related requests. GET gets all of the current orphans.
    DELETE removes all orphans (requires is_staff access)

    An orphan is a block whose category is not in the DETACHED_CATEGORY list, is not the root, and is not reachable
    from the root via children
    """
    course_usage_key = CourseKey.from_string(course_key_string)
    if request.method == 'GET':
        if has_course_access(request.user, course_usage_key):
            return JsonResponse(modulestore().get_orphans(course_usage_key))
        else:
            raise PermissionDenied()
    if request.method == 'DELETE':
        if request.user.is_staff:
            items = modulestore().get_orphans(course_usage_key)
            for itemloc in items:
                # get_orphans returns the deprecated string format
                usage_key = course_usage_key.make_usage_key_from_deprecated_string(
                    itemloc)
                modulestore('draft').delete_item(usage_key,
                                                 delete_all_versions=True)
            return JsonResponse({'deleted': items})
        else:
            raise PermissionDenied()
Пример #7
0
    def parse_args(self, *args):
        """
        Return a 4-tuple of (course_key, user, org, offering).
        If the user didn't specify an org & offering, those will be None.
        """
        if len(args) < 2:
            raise CommandError(
                "migrate_to_split requires at least two arguments: "
                "a course_key and a user identifier (email or ID)"
            )

        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        try:
            user = user_from_str(args[1])
        except User.DoesNotExist:
            raise CommandError("No user found identified by {}".format(args[1]))

        try:
            org = args[2]
            offering = args[3]
        except IndexError:
            org = offering = None

        return course_key, user, org, offering
Пример #8
0
    def handle(self, *args, **options):
        if not options["course"]:
            raise CommandError(Command.course_option.help)

        try:
            course_key = CourseKey.from_string(options["course"])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(options["course"])

        course = get_course_by_id(course_key)

        print "Warning: this command directly edits the list of course tabs in mongo."
        print "Tabs before any changes:"
        print_course(course)

        try:
            if options["delete"]:
                if len(args) != 1:
                    raise CommandError(Command.delete_option.help)
                num = int(args[0])
                if query_yes_no("Deleting tab {0} Confirm?".format(num), default="no"):
                    tabs.primitive_delete(course, num - 1)  # -1 for 0-based indexing
            elif options["insert"]:
                if len(args) != 3:
                    raise CommandError(Command.insert_option.help)
                num = int(args[0])
                tab_type = args[1]
                name = args[2]
                if query_yes_no('Inserting tab {0} "{1}" "{2}" Confirm?'.format(num, tab_type, name), default="no"):
                    tabs.primitive_insert(course, num - 1, tab_type, name)  # -1 as above
        except ValueError as e:
            # Cute: translate to CommandError so the CLI error prints nicely.
            raise CommandError(e)
Пример #9
0
    def handle(self, *args, **options):
        """
        Checks arguments and runs export function if they are good
        """

        if len(args) != 2:
            raise CommandError('This script requires exactly two arguments: '
                               'course_loc and git_url')

        # Rethrow GitExportError as CommandError for SystemExit
        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])
            except InvalidKeyError:
                raise CommandError(GitExportError.BAD_COURSE)

        try:
            git_export_utils.export_to_git(
                course_key,
                args[1],
                options.get('user', ''),
                options.get('rdir', None)
            )
        except git_export_utils.GitExportError as ex:
            raise CommandError(str(ex))
Пример #10
0
    def handle(self, *args, **options):
        """
        Checks arguments and runs export function if they are good
        """

        if len(args) != 2:
            raise CommandError('This script requires exactly two arguments: '
                               'course_loc and git_url')

        # Rethrow GitExportError as CommandError for SystemExit
        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(
                    args[0])
            except InvalidKeyError:
                raise CommandError(GitExportError.BAD_COURSE)

        try:
            git_export_utils.export_to_git(course_key, args[1],
                                           options.get('user', ''),
                                           options.get('rdir', None))
        except git_export_utils.GitExportError as ex:
            raise CommandError(str(ex))
Пример #11
0
    def handle(self, *args, **options):

        print "args = ", args

        if len(args) > 0:
            course_id = args[0]
        else:
            print self.help
            return
        course_key = None
        # parse out the course id into a coursekey
        try:
            course_key = CourseKey.from_string(course_id)
        # if it's not a new-style course key, parse it from an old-style
        # course key
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        try:
            course = get_course_by_id(course_key)
        except Exception as err:
            print "-----------------------------------------------------------------------------"
            print "Sorry, cannot find course with id {}".format(course_id)
            print "Got exception {}".format(err)
            print "Please provide a course ID or course data directory name, eg content-mit-801rq"
            return

        print "-----------------------------------------------------------------------------"
        print "Computing grades for {}".format(course_id)

        offline_grade_calculation(course_key)
Пример #12
0
    def handle(self, *args, **options):
        if not options['course_id']:
            raise CommandError("You must specify a course id for this command")
        if not options['from_mode'] or not options['to_mode']:
            raise CommandError('You must specify a "to" and "from" mode as parameters')

        try:
            course_key = CourseKey.from_string(options['course_id'])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(options['course_id'])

        filter_args = dict(
            course_id=course_key,
            mode=options['from_mode']
        )
        if options['user']:
            if '@' in options['user']:
                user = User.objects.get(email=options['user'])
            else:
                user = User.objects.get(username=options['user'])
            filter_args['user'] = user
        enrollments = CourseEnrollment.objects.filter(**filter_args)
        if options['noop']:
            print "Would have changed {num_enrollments} students from {from_mode} to {to_mode}".format(
                num_enrollments=enrollments.count(),
                from_mode=options['from_mode'],
                to_mode=options['to_mode']
            )
        else:
            for enrollment in enrollments:
                enrollment.update_enrollment(mode=options['to_mode'])
                enrollment.save()
Пример #13
0
    def handle(self, *args, **options):

        print "args = ", args

        if len(args) > 0:
            course_id = args[0]
        else:
            print self.help
            return
        course_key = None
        # parse out the course id into a coursekey
        try:
            course_key = CourseKey.from_string(course_id)
        # if it's not a new-style course key, parse it from an old-style
        # course key
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                course_id)
        try:
            _course = get_course_by_id(course_key)
        except Exception as err:
            print "-----------------------------------------------------------------------------"
            print "Sorry, cannot find course with id {}".format(course_id)
            print "Got exception {}".format(err)
            print "Please provide a course ID or course data directory name, eg content-mit-801rq"
            return

        print "-----------------------------------------------------------------------------"
        print "Computing grades for {}".format(course_id)

        offline_grade_calculation(course_key)
Пример #14
0
 def course_key_from_arg(self, arg):
     """
     Convert the command line arg into a course key
     """
     try:
         return CourseKey.from_string(arg)
     except InvalidKeyError:
         return SlashSeparatedCourseKey.from_deprecated_string(arg)
Пример #15
0
    def handle(self, *args, **options):

        # current grading logic and data schema doesn't handle dates
        # datetime.strptime("21/11/06 16:30", "%m/%d/%y %H:%M")

        print "args = ", args

        course_id = 'MITx/8.01rq_MW/Classical_Mechanics_Reading_Questions_Fall_2012_MW_Section'
        fn = "grades.csv"
        get_raw_scores = False

        if len(args) > 0:
            course_id = args[0]
        if len(args) > 1:
            fn = args[1]
        if len(args) > 2:
            get_raw_scores = args[2].lower() == 'raw'

        request = DummyRequest()
        # parse out the course into a coursekey
        try:
            course_key = CourseKey.from_string(course_id)
        # if it's not a new-style course key, parse it from an old-style
        # course key
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                course_id)

        try:
            course = get_course_by_id(course_key)
        # Ok with catching general exception here because this is run as a management command
        # and the exception is exposed right away to the user.
        except Exception as err:  # pylint: disable=broad-except
            print "-----------------------------------------------------------------------------"
            print "Sorry, cannot find course with id {}".format(course_id)
            print "Got exception {}".format(err)
            print "Please provide a course ID or course data directory name, eg content-mit-801rq"
            return

        print "-----------------------------------------------------------------------------"
        print "Dumping grades from {} to file {} (get_raw_scores={})".format(
            course.id, fn, get_raw_scores)
        datatable = get_student_grade_summary_data(
            request, course, get_raw_scores=get_raw_scores)

        fp = open(fn, 'w')

        writer = csv.writer(fp,
                            dialect='excel',
                            quotechar='"',
                            quoting=csv.QUOTE_ALL)
        writer.writerow(datatable['header'])
        for datarow in datatable['data']:
            encoded_row = [unicode(s).encode('utf-8') for s in datarow]
            writer.writerow(encoded_row)

        fp.close()
        print "Done: {} records dumped".format(len(datatable['data']))
Пример #16
0
def tabs_handler(request, course_key_string):
    """
    The restful handler for static tabs.

    GET
        html: return page for editing static tabs
        json: not supported
    PUT or POST
        json: update the tab order. It is expected that the request body contains a JSON-encoded dict with entry "tabs".
        The value for "tabs" is an array of tab locators, indicating the desired order of the tabs.

    Creating a tab, deleting a tab, or changing its contents is not supported through this method.
    Instead use the general xblock URL (see item.xblock_handler).
    """
    course_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    course_item = modulestore().get_course(course_key)

    if 'application/json' in request.META.get('HTTP_ACCEPT',
                                              'application/json'):
        if request.method == 'GET':
            raise NotImplementedError('coming soon')
        else:
            if 'tabs' in request.json:
                return reorder_tabs_handler(course_item, request)
            elif 'tab_id_locator' in request.json:
                return edit_tab_handler(course_item, request)
            else:
                raise NotImplementedError(
                    'Creating or changing tab content is not supported.')

    elif request.method == 'GET':  # assume html
        # get all tabs from the tabs list: static tabs (a.k.a. user-created tabs) and built-in tabs
        # present in the same order they are displayed in LMS

        tabs_to_render = []
        for tab in CourseTabList.iterate_displayable_cms(
                course_item,
                settings,
        ):
            if isinstance(tab, StaticTab):
                # static tab needs its locator information to render itself as an xmodule
                static_tab_loc = course_key.make_usage_key(
                    'static_tab', tab.url_slug)
                tab.locator = static_tab_loc
            tabs_to_render.append(tab)

        return render_to_response(
            'edit-tabs.html', {
                'context_course': course_item,
                'tabs_to_render': tabs_to_render,
                'lms_link': get_lms_link_for_item(course_item.location),
            })
    else:
        return HttpResponseNotFound()
Пример #17
0
 def test_course_constructor_url_package_id_and_version_guid(self):
     test_id_loc = '519665f6223ebd6980884f2b'
     testobj = CourseKey.from_string(
         'course-locator:mit.eecs+honors.6002x+{}+{}'.format(
             CourseLocator.VERSION_PREFIX, test_id_loc))
     self.check_course_locn_fields(testobj,
                                   org='mit.eecs',
                                   offering='honors.6002x',
                                   version_guid=ObjectId(test_id_loc))
Пример #18
0
 def test_course_constructor_url(self):
     # Test parsing a url when it starts with a version ID and there is also a block ID.
     # This hits the parsers parse_guid method.
     test_id_loc = '519665f6223ebd6980884f2b'
     testobj = CourseKey.from_string("course-locator:{}+{}+{}+hw3".format(
         CourseLocator.VERSION_PREFIX, test_id_loc,
         CourseLocator.BLOCK_PREFIX))
     self.check_course_locn_fields(testobj,
                                   version_guid=ObjectId(test_id_loc))
Пример #19
0
def course_handler(request, course_key_string=None):
    """
    The restful handler for course specific requests.
    It provides the course tree with the necessary information for identifying and labeling the parts. The root
    will typically be a 'course' object but may not be especially as we support modules.

    GET
        html: return course listing page if not given a course id
        html: return html page overview for the given course if given a course id
        json: return json representing the course branch's index entry as well as dag w/ all of the children
        replaced w/ json docs where each doc has {'_id': , 'display_name': , 'children': }
    POST
        json: create a course, return resulting json
        descriptor (same as in GET course/...). Leaving off /branch/draft would imply create the course w/ default
        branches. Cannot change the structure contents ('_id', 'display_name', 'children') but can change the
        index entry.
    PUT
        json: update this course (index entry not xblock) such as repointing head, changing display name, org,
        offering. Return same json as above.
    DELETE
        json: delete this branch from this course (leaving off /branch/draft would imply delete the course)
    """
    response_format = request.REQUEST.get("format", "html")
    if response_format == "json" or "application/json" in request.META.get("HTTP_ACCEPT", "application/json"):
        if request.method == "GET":
            return JsonResponse(_course_json(request, CourseKey.from_string(course_key_string)))
        elif request.method == "POST":  # not sure if this is only post. If one will have ids, it goes after access
            return create_new_course(request)
        elif not has_course_access(request.user, CourseKey.from_string(course_key_string)):
            raise PermissionDenied()
        elif request.method == "PUT":
            raise NotImplementedError()
        elif request.method == "DELETE":
            raise NotImplementedError()
        else:
            return HttpResponseBadRequest()
    elif request.method == "GET":  # assume html
        if course_key_string is None:
            return course_listing(request)
        else:
            return course_index(request, CourseKey.from_string(course_key_string))
    else:
        return HttpResponseNotFound()
Пример #20
0
 def test_course_constructor_url_package_id_and_version_guid(self):
     test_id_loc = '519665f6223ebd6980884f2b'
     testobj = CourseKey.from_string(
         'course-locator:mit.eecs+honors.6002x+{}+{}'.format(CourseLocator.VERSION_PREFIX, test_id_loc)
     )
     self.check_course_locn_fields(
         testobj,
         org='mit.eecs',
         offering='honors.6002x',
         version_guid=ObjectId(test_id_loc)
     )
Пример #21
0
 def test_course_constructor_url(self):
     # Test parsing a url when it starts with a version ID and there is also a block ID.
     # This hits the parsers parse_guid method.
     test_id_loc = '519665f6223ebd6980884f2b'
     testobj = CourseKey.from_string("course-locator:{}+{}+{}+hw3".format(
         CourseLocator.VERSION_PREFIX, test_id_loc, CourseLocator.BLOCK_PREFIX
     ))
     self.check_course_locn_fields(
         testobj,
         version_guid=ObjectId(test_id_loc)
     )
Пример #22
0
def textbooks_detail_handler(request, course_key_string, textbook_id):
    """
    JSON API endpoint for manipulating a textbook via its internal ID.
    Used by the Backbone application.

    GET
        json: return JSON representation of textbook
    POST or PUT
        json: update textbook based on provided information
    DELETE
        json: remove textbook
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    store = get_modulestore(course_module.location)
    matching_id = [
        tb for tb in course_module.pdf_textbooks
        if unicode(tb.get("id")) == unicode(textbook_id)
    ]
    if matching_id:
        textbook = matching_id[0]
    else:
        textbook = None

    if request.method == 'GET':
        if not textbook:
            return JsonResponse(status=404)
        return JsonResponse(textbook)
    elif request.method in ('POST', 'PUT'):  # can be either and sometimes
        # django is rewriting one to the other
        try:
            new_textbook = validate_textbook_json(request.body)
        except TextbookValidationError as err:
            return JsonResponse({"error": err.message}, status=400)
        new_textbook["id"] = textbook_id
        if textbook:
            i = course_module.pdf_textbooks.index(textbook)
            new_textbooks = course_module.pdf_textbooks[0:i]
            new_textbooks.append(new_textbook)
            new_textbooks.extend(course_module.pdf_textbooks[i + 1:])
            course_module.pdf_textbooks = new_textbooks
        else:
            course_module.pdf_textbooks.append(new_textbook)
        store.update_item(course_module, request.user.id)
        return JsonResponse(new_textbook, status=201)
    elif request.method == 'DELETE':
        if not textbook:
            return JsonResponse(status=404)
        i = course_module.pdf_textbooks.index(textbook)
        remaining_textbooks = course_module.pdf_textbooks[0:i]
        remaining_textbooks.extend(course_module.pdf_textbooks[i + 1:])
        course_module.pdf_textbooks = remaining_textbooks
        store.update_item(course_module, request.user.id)
        return JsonResponse()
Пример #23
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("check_course requires one argument: <course_id>")

        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        store = modulestore()

        course = store.get_course(course_key, depth=3)

        err_cnt = 0

        def _xlint_metadata(module):
            err_cnt = check_module_metadata_editability(module)
            for child in module.get_children():
                err_cnt = err_cnt + _xlint_metadata(child)
            return err_cnt

        err_cnt = err_cnt + _xlint_metadata(course)

        # we've had a bug where the xml_attributes field can we rewritten as a string rather than a dict
        def _check_xml_attributes_field(module):
            err_cnt = 0
            if hasattr(module, 'xml_attributes') and isinstance(module.xml_attributes, basestring):
                print 'module = {0} has xml_attributes as a string. It should be a dict'.format(module.location)
                err_cnt = err_cnt + 1
            for child in module.get_children():
                err_cnt = err_cnt + _check_xml_attributes_field(child)
            return err_cnt

        err_cnt = err_cnt + _check_xml_attributes_field(course)

        # check for dangling discussion items, this can cause errors in the forums
        def _get_discussion_items(module):
            discussion_items = []
            if module.location.category == 'discussion':
                discussion_items = discussion_items + [module.location]

            for child in module.get_children():
                discussion_items = discussion_items + _get_discussion_items(child)

            return discussion_items

        discussion_items = _get_discussion_items(course)

        # now query all discussion items via get_items() and compare with the tree-traversal
        queried_discussion_items = store.get_items(course_key=course_key, category='discussion',)

        for item in queried_discussion_items:
            if item.location not in discussion_items:
                print 'Found dangling discussion module = {0}'.format(item.location)
Пример #24
0
def settings_handler(request, course_key_string):
    """
    Course settings for dates and about pages
    GET
        html: get the page
        json: get the CourseDetails model
    PUT
        json: update the Course and About xblocks through the CourseDetails model
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if 'text/html' in request.META.get('HTTP_ACCEPT',
                                       '') and request.method == 'GET':
        upload_asset_url = reverse_course_url('assets_handler', course_key)

        # see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
        # course about page should be editable in Studio
        about_page_editable = not microsite.get_value_for_org(
            course_module.location.org, 'ENABLE_MKTG_SITE',
            settings.FEATURES.get('ENABLE_MKTG_SITE', False))

        short_description_editable = settings.FEATURES.get(
            'EDITABLE_SHORT_DESCRIPTION', True)

        return render_to_response(
            'settings.html', {
                'context_course':
                course_module,
                'course_locator':
                course_key,
                'lms_link_for_about_page':
                utils.get_lms_link_for_about_page(course_key),
                'course_image_url':
                utils.course_image_url(course_module),
                'details_url':
                reverse_course_url('settings_handler', course_key),
                'about_page_editable':
                about_page_editable,
                'short_description_editable':
                short_description_editable,
                'upload_asset_url':
                upload_asset_url
            })
    elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
        if request.method == 'GET':
            return JsonResponse(
                CourseDetails.fetch(course_key),
                # encoder serializes dates, old locations, and instances
                encoder=CourseSettingsEncoder)
        else:  # post or put, doesn't matter.
            return JsonResponse(CourseDetails.update_from_json(
                course_key, request.json, request.user),
                                encoder=CourseSettingsEncoder)
Пример #25
0
def grading_handler(request, course_key_string, grader_index=None):
    """
    Course Grading policy configuration
    GET
        html: get the page
        json no grader_index: get the CourseGrading model (graceperiod, cutoffs, and graders)
        json w/ grader_index: get the specific grader
    PUT
        json no grader_index: update the Course through the CourseGrading model
        json w/ grader_index: create or update the specific grader (create if index out of range)
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)

    if 'text/html' in request.META.get('HTTP_ACCEPT',
                                       '') and request.method == 'GET':
        course_details = CourseGradingModel.fetch(course_key)

        return render_to_response(
            'settings_graders.html', {
                'context_course':
                course_module,
                'course_locator':
                course_key,
                'course_details':
                json.dumps(course_details, cls=CourseSettingsEncoder),
                'grading_url':
                reverse_course_url('grading_handler', course_key),
            })
    elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
        if request.method == 'GET':
            if grader_index is None:
                return JsonResponse(
                    CourseGradingModel.fetch(course_key),
                    # encoder serializes dates, old locations, and instances
                    encoder=CourseSettingsEncoder)
            else:
                return JsonResponse(
                    CourseGradingModel.fetch_grader(course_key, grader_index))
        elif request.method in ('POST', 'PUT'):  # post or put, doesn't matter.
            # None implies update the whole model (cutoffs, graceperiod, and graders) not a specific grader
            if grader_index is None:
                return JsonResponse(CourseGradingModel.update_from_json(
                    course_key, request.json, request.user),
                                    encoder=CourseSettingsEncoder)
            else:
                return JsonResponse(
                    CourseGradingModel.update_grader_from_json(
                        course_key, request.json, request.user))
        elif request.method == "DELETE" and grader_index is not None:
            CourseGradingModel.delete_grader(course_key, grader_index,
                                             request.user)
            return JsonResponse()
Пример #26
0
def tabs_handler(request, course_key_string):
    """
    The restful handler for static tabs.

    GET
        html: return page for editing static tabs
        json: not supported
    PUT or POST
        json: update the tab order. It is expected that the request body contains a JSON-encoded dict with entry "tabs".
        The value for "tabs" is an array of tab locators, indicating the desired order of the tabs.

    Creating a tab, deleting a tab, or changing its contents is not supported through this method.
    Instead use the general xblock URL (see item.xblock_handler).
    """
    course_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    course_item = modulestore().get_course(course_key)

    if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):
        if request.method == 'GET':
            raise NotImplementedError('coming soon')
        else:
            if 'tabs' in request.json:
                return reorder_tabs_handler(course_item, request)
            elif 'tab_id_locator' in request.json:
                return edit_tab_handler(course_item, request)
            else:
                raise NotImplementedError('Creating or changing tab content is not supported.')

    elif request.method == 'GET':  # assume html
        # get all tabs from the tabs list: static tabs (a.k.a. user-created tabs) and built-in tabs
        # present in the same order they are displayed in LMS

        tabs_to_render = []
        for tab in CourseTabList.iterate_displayable_cms(
                course_item,
                settings,
        ):
            if isinstance(tab, StaticTab):
                # static tab needs its locator information to render itself as an xmodule
                static_tab_loc = course_key.make_usage_key('static_tab', tab.url_slug)
                tab.locator = static_tab_loc
            tabs_to_render.append(tab)

        return render_to_response('edit-tabs.html', {
            'context_course': course_item,
            'tabs_to_render': tabs_to_render,
            'lms_link': get_lms_link_for_item(course_item.location),
        })
    else:
        return HttpResponseNotFound()
Пример #27
0
def textbooks_detail_handler(request, course_key_string, textbook_id):
    """
    JSON API endpoint for manipulating a textbook via its internal ID.
    Used by the Backbone application.

    GET
        json: return JSON representation of textbook
    POST or PUT
        json: update textbook based on provided information
    DELETE
        json: remove textbook
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    store = get_modulestore(course_module.location)
    matching_id = [tb for tb in course_module.pdf_textbooks
                   if unicode(tb.get("id")) == unicode(textbook_id)]
    if matching_id:
        textbook = matching_id[0]
    else:
        textbook = None

    if request.method == 'GET':
        if not textbook:
            return JsonResponse(status=404)
        return JsonResponse(textbook)
    elif request.method in ('POST', 'PUT'):  # can be either and sometimes
                                        # django is rewriting one to the other
        try:
            new_textbook = validate_textbook_json(request.body)
        except TextbookValidationError as err:
            return JsonResponse({"error": err.message}, status=400)
        new_textbook["id"] = textbook_id
        if textbook:
            i = course_module.pdf_textbooks.index(textbook)
            new_textbooks = course_module.pdf_textbooks[0:i]
            new_textbooks.append(new_textbook)
            new_textbooks.extend(course_module.pdf_textbooks[i + 1:])
            course_module.pdf_textbooks = new_textbooks
        else:
            course_module.pdf_textbooks.append(new_textbook)
        store.update_item(course_module, request.user.id)
        return JsonResponse(new_textbook, status=201)
    elif request.method == 'DELETE':
        if not textbook:
            return JsonResponse(status=404)
        i = course_module.pdf_textbooks.index(textbook)
        remaining_textbooks = course_module.pdf_textbooks[0:i]
        remaining_textbooks.extend(course_module.pdf_textbooks[i + 1:])
        course_module.pdf_textbooks = remaining_textbooks
        store.update_item(course_module, request.user.id)
        return JsonResponse()
Пример #28
0
    def handle(self, *args, **options):

        # current grading logic and data schema doesn't handle dates
        # datetime.strptime("21/11/06 16:30", "%m/%d/%y %H:%M")

        print "args = ", args

        course_id = 'MITx/8.01rq_MW/Classical_Mechanics_Reading_Questions_Fall_2012_MW_Section'
        fn = "grades.csv"
        get_raw_scores = False

        if len(args) > 0:
            course_id = args[0]
        if len(args) > 1:
            fn = args[1]
        if len(args) > 2:
            get_raw_scores = args[2].lower() == 'raw'

        request = DummyRequest()
        # parse out the course into a coursekey
        try:
            course_key = CourseKey.from_string(course_id)
        # if it's not a new-style course key, parse it from an old-style
        # course key
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

        try:
            course = get_course_by_id(course_key)
        # Ok with catching general exception here because this is run as a management command
        # and the exception is exposed right away to the user.
        except Exception as err:  # pylint: disable=broad-except
            print "-----------------------------------------------------------------------------"
            print "Sorry, cannot find course with id {}".format(course_id)
            print "Got exception {}".format(err)
            print "Please provide a course ID or course data directory name, eg content-mit-801rq"
            return

        print "-----------------------------------------------------------------------------"
        print "Dumping grades from {} to file {} (get_raw_scores={})".format(course.id, fn, get_raw_scores)
        datatable = get_student_grade_summary_data(request, course, get_raw_scores=get_raw_scores)

        fp = open(fn, 'w')

        writer = csv.writer(fp, dialect='excel', quotechar='"', quoting=csv.QUOTE_ALL)
        writer.writerow(datatable['header'])
        for datarow in datatable['data']:
            encoded_row = [unicode(s).encode('utf-8') for s in datarow]
            writer.writerow(encoded_row)

        fp.close()
        print "Done: {} records dumped".format(len(datatable['data']))
Пример #29
0
 def test_course_constructor_url_package_id_branch_and_version_guid(self):
     test_id_loc = '519665f6223ebd6980884f2b'
     org = 'mit.eecs'
     offering = '~6002x'
     testobj = CourseKey.from_string(
         'course-locator:{}+{}+{}+draft-1+{}+{}'.format(
             org, offering, CourseLocator.BRANCH_PREFIX,
             CourseLocator.VERSION_PREFIX, test_id_loc))
     self.check_course_locn_fields(testobj,
                                   org=org,
                                   offering=offering,
                                   branch='draft-1',
                                   version_guid=ObjectId(test_id_loc))
Пример #30
0
 def test_course_constructor_url_package_id_branch_and_version_guid(self):
     test_id_loc = '519665f6223ebd6980884f2b'
     org = 'mit.eecs'
     offering = '~6002x'
     testobj = CourseKey.from_string('course-locator:{}+{}+{}+draft-1+{}+{}'.format(
         org, offering, CourseLocator.BRANCH_PREFIX, CourseLocator.VERSION_PREFIX, test_id_loc
     ))
     self.check_course_locn_fields(
         testobj,
         org=org,
         offering=offering,
         branch='draft-1',
         version_guid=ObjectId(test_id_loc)
     )
Пример #31
0
    def clean_course_id(self):
        course_id = self.cleaned_data['course_id']
        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            try:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
            except InvalidKeyError:
                raise forms.ValidationError("Cannot make a valid CourseKey from id {}!".format(course_id))

        if not modulestore().has_course(course_key):
            raise forms.ValidationError("Cannot find course with id {} in the modulestore".format(course_id))

        return course_key
Пример #32
0
def course_info_update_handler(request, course_key_string, provided_id=None):
    """
    restful CRUD operations on course_info updates.
    provided_id should be none if it's new (create) and index otherwise.
    GET
        json: return the course info update models
    POST
        json: create an update
    PUT or DELETE
        json: change an existing update
    """
    if 'application/json' not in request.META.get('HTTP_ACCEPT',
                                                  'application/json'):
        return HttpResponseBadRequest("Only supports json requests")

    course_key = CourseKey.from_string(course_key_string)
    usage_key = course_key.make_usage_key('course_info', 'updates')
    if provided_id == '':
        provided_id = None

    # check that logged in user has permissions to this item (GET shouldn't require this level?)
    if not has_course_access(request.user, usage_key.course_key):
        raise PermissionDenied()

    if request.method == 'GET':
        course_updates = get_course_updates(usage_key, provided_id)
        if isinstance(course_updates, dict) and course_updates.get('error'):
            return JsonResponse(course_updates,
                                course_updates.get('status', 400))
        else:
            return JsonResponse(course_updates)
    elif request.method == 'DELETE':
        try:
            return JsonResponse(
                delete_course_update(usage_key, request.json, provided_id,
                                     request.user))
        except:
            return HttpResponseBadRequest("Failed to delete",
                                          content_type="text/plain")
    # can be either and sometimes django is rewriting one to the other:
    elif request.method in ('POST', 'PUT'):
        try:
            return JsonResponse(
                update_course_updates(usage_key, request.json, provided_id,
                                      request.user))
        except:
            return HttpResponseBadRequest("Failed to save",
                                          content_type="text/plain")
Пример #33
0
def grading_handler(request, course_key_string, grader_index=None):
    """
    Course Grading policy configuration
    GET
        html: get the page
        json no grader_index: get the CourseGrading model (graceperiod, cutoffs, and graders)
        json w/ grader_index: get the specific grader
    PUT
        json no grader_index: update the Course through the CourseGrading model
        json w/ grader_index: create or update the specific grader (create if index out of range)
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)

    if "text/html" in request.META.get("HTTP_ACCEPT", "") and request.method == "GET":
        course_details = CourseGradingModel.fetch(course_key)

        return render_to_response(
            "settings_graders.html",
            {
                "context_course": course_module,
                "course_locator": course_key,
                "course_details": json.dumps(course_details, cls=CourseSettingsEncoder),
                "grading_url": reverse_course_url("grading_handler", course_key),
            },
        )
    elif "application/json" in request.META.get("HTTP_ACCEPT", ""):
        if request.method == "GET":
            if grader_index is None:
                return JsonResponse(
                    CourseGradingModel.fetch(course_key),
                    # encoder serializes dates, old locations, and instances
                    encoder=CourseSettingsEncoder,
                )
            else:
                return JsonResponse(CourseGradingModel.fetch_grader(course_key, grader_index))
        elif request.method in ("POST", "PUT"):  # post or put, doesn't matter.
            # None implies update the whole model (cutoffs, graceperiod, and graders) not a specific grader
            if grader_index is None:
                return JsonResponse(
                    CourseGradingModel.update_from_json(course_key, request.json, request.user),
                    encoder=CourseSettingsEncoder,
                )
            else:
                return JsonResponse(CourseGradingModel.update_grader_from_json(course_key, request.json, request.user))
        elif request.method == "DELETE" and grader_index is not None:
            CourseGradingModel.delete_grader(course_key, grader_index, request.user)
            return JsonResponse()
Пример #34
0
    def handle(self, *args, **options):
        if len(args) < 1 or len(args) > 2:
            print Command.help
            return

        num = int(args[0])

        if len(args) == 2:
            try:
                course_key = CourseKey.from_string(args[1])
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(args[1])
        else:
            course_key = None

        create(num, course_key)
Пример #35
0
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 0:
            raise CommandError("empty_asset_trashcan requires one or no arguments: |<course_id>|")

        if len(args) == 1:
            try:
                course_key = CourseKey.from_string(args[0])
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

            course_ids = [course_key]
        else:
            course_ids = [course.id for course in modulestore('direct').get_courses()]

        if query_yes_no("Emptying trashcan. Confirm?", default="no"):
            empty_asset_trashcan(course_ids)
Пример #36
0
def settings_handler(request, course_key_string):
    """
    Course settings for dates and about pages
    GET
        html: get the page
        json: get the CourseDetails model
    PUT
        json: update the Course and About xblocks through the CourseDetails model
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if "text/html" in request.META.get("HTTP_ACCEPT", "") and request.method == "GET":
        upload_asset_url = reverse_course_url("assets_handler", course_key)

        # see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
        # course about page should be editable in Studio
        about_page_editable = not microsite.get_value_for_org(
            course_module.location.org, "ENABLE_MKTG_SITE", settings.FEATURES.get("ENABLE_MKTG_SITE", False)
        )

        short_description_editable = settings.FEATURES.get("EDITABLE_SHORT_DESCRIPTION", True)

        return render_to_response(
            "settings.html",
            {
                "context_course": course_module,
                "course_locator": course_key,
                "lms_link_for_about_page": utils.get_lms_link_for_about_page(course_key),
                "course_image_url": utils.course_image_url(course_module),
                "details_url": reverse_course_url("settings_handler", course_key),
                "about_page_editable": about_page_editable,
                "short_description_editable": short_description_editable,
                "upload_asset_url": upload_asset_url,
            },
        )
    elif "application/json" in request.META.get("HTTP_ACCEPT", ""):
        if request.method == "GET":
            return JsonResponse(
                CourseDetails.fetch(course_key),
                # encoder serializes dates, old locations, and instances
                encoder=CourseSettingsEncoder,
            )
        else:  # post or put, doesn't matter.
            return JsonResponse(
                CourseDetails.update_from_json(course_key, request.json, request.user), encoder=CourseSettingsEncoder
            )
Пример #37
0
def course_info_update_handler(request, course_key_string, provided_id=None):
    """
    restful CRUD operations on course_info updates.
    provided_id should be none if it's new (create) and index otherwise.
    GET
        json: return the course info update models
    POST
        json: create an update
    PUT or DELETE
        json: change an existing update
    """
    if 'application/json' not in request.META.get('HTTP_ACCEPT', 'application/json'):
        return HttpResponseBadRequest("Only supports json requests")

    course_key = CourseKey.from_string(course_key_string)
    usage_key = course_key.make_usage_key('course_info', 'updates')
    if provided_id == '':
        provided_id = None

    # check that logged in user has permissions to this item (GET shouldn't require this level?)
    if not has_course_access(request.user, usage_key.course_key):
        raise PermissionDenied()

    if request.method == 'GET':
        course_updates = get_course_updates(usage_key, provided_id)
        if isinstance(course_updates, dict) and course_updates.get('error'):
            return JsonResponse(course_updates, course_updates.get('status', 400))
        else:
            return JsonResponse(course_updates)
    elif request.method == 'DELETE':
        try:
            return JsonResponse(delete_course_update(usage_key, request.json, provided_id, request.user))
        except:
            return HttpResponseBadRequest(
                "Failed to delete",
                content_type="text/plain"
            )
    # can be either and sometimes django is rewriting one to the other:
    elif request.method in ('POST', 'PUT'):
        try:
            return JsonResponse(update_course_updates(usage_key, request.json, provided_id, request.user))
        except:
            return HttpResponseBadRequest(
                "Failed to save",
                content_type="text/plain"
            )
Пример #38
0
def settings_handler(request, course_key_string):
    """
    Course settings for dates and about pages
    GET
        html: get the page
        json: get the CourseDetails model
    PUT
        json: update the Course and About xblocks through the CourseDetails model
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
        upload_asset_url = reverse_course_url('assets_handler', course_key)

        # see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
        # course about page should be editable in Studio
        about_page_editable = not microsite.get_value_for_org(
            course_module.location.org,
            'ENABLE_MKTG_SITE',
            settings.FEATURES.get('ENABLE_MKTG_SITE', False)
        )

        short_description_editable = settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True)

        return render_to_response('settings.html', {
            'context_course': course_module,
            'course_locator': course_key,
            'lms_link_for_about_page': utils.get_lms_link_for_about_page(course_key),
            'course_image_url': utils.course_image_url(course_module),
            'details_url': reverse_course_url('settings_handler', course_key),
            'about_page_editable': about_page_editable,
            'short_description_editable': short_description_editable,
            'upload_asset_url': upload_asset_url
        })
    elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
        if request.method == 'GET':
            return JsonResponse(
                CourseDetails.fetch(course_key),
                # encoder serializes dates, old locations, and instances
                encoder=CourseSettingsEncoder
            )
        else:  # post or put, doesn't matter.
            return JsonResponse(
                CourseDetails.update_from_json(course_key, request.json, request.user),
                encoder=CourseSettingsEncoder
            )
    def handle(self, *args, **options):
        if len(args) < 1 or len(args) > 2:
            print Command.help
            return

        num = int(args[0])

        if len(args) == 2:
            try:
                course_key = CourseKey.from_string(args[1])
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(
                    args[1])
        else:
            course_key = None

        create(num, course_key)
Пример #40
0
    def handle(self, *args, **options):
        username = options['username']
        name = options['name']
        if not username:
            username = options['email'].split('@')[0]
        if not name:
            name = options['email'].split('@')[0]

        # parse out the course into a coursekey
        if options['course']:
            try:
                course = CourseKey.from_string(options['course'])
            # if it's not a new-style course key, parse it from an old-style
            # course key
            except InvalidKeyError:
                course = SlashSeparatedCourseKey.from_deprecated_string(
                    options['course'])

        post_data = {
            'username': username,
            'email': options['email'],
            'password': options['password'],
            'name': name,
            'honor_code': u'true',
            'terms_of_service': u'true',
        }
        # django.utils.translation.get_language() will be used to set the new
        # user's preferred language.  This line ensures that the result will
        # match this installation's default locale.  Otherwise, inside a
        # management command, it will always return "en-us".
        translation.activate(settings.LANGUAGE_CODE)
        try:
            user, profile, reg = _do_create_account(post_data)
            if options['staff']:
                user.is_staff = True
                user.save()
            reg.activate()
            reg.save()
            create_comments_service_user(user)
        except AccountValidationError as e:
            print e.message
            user = User.objects.get(email=options['email'])
        if options['course']:
            CourseEnrollment.enroll(user, course, mode=options['mode'])
        translation.deactivate()
Пример #41
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) != 2:
            raise CommandError("export requires two arguments: <course id> <output path>")

        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        output_path = args[1]

        print("Exporting course id = {0} to {1}".format(course_key, output_path))

        root_dir = os.path.dirname(output_path)
        course_dir = os.path.splitext(os.path.basename(output_path))[0]

        export_to_xml(modulestore('direct'), contentstore(), course_key, root_dir, course_dir, modulestore())
Пример #42
0
def advanced_settings_handler(request, course_key_string):
    """
    Course settings configuration
    GET
        html: get the page
        json: get the model
    PUT, POST
        json: update the Course's settings. The payload is a json rep of the
            metadata dicts. The dict can include a "unsetKeys" entry which is a list
            of keys whose values to unset: i.e., revert to default
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if 'text/html' in request.META.get('HTTP_ACCEPT',
                                       '') and request.method == 'GET':

        return render_to_response(
            'settings_advanced.html', {
                'context_course':
                course_module,
                'advanced_dict':
                json.dumps(CourseMetadata.fetch(course_module)),
                'advanced_settings_url':
                reverse_course_url('advanced_settings_handler', course_key)
            })
    elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
        if request.method == 'GET':
            return JsonResponse(CourseMetadata.fetch(course_module))
        else:
            # Whether or not to filter the tabs key out of the settings metadata
            filter_tabs = _config_course_advanced_components(
                request, course_module)
            try:
                return JsonResponse(
                    CourseMetadata.update_from_json(
                        course_module,
                        request.json,
                        filter_tabs=filter_tabs,
                        user=request.user,
                    ))
            except (TypeError, ValueError) as err:
                return HttpResponseBadRequest(
                    "Incorrect setting format. {}".format(err),
                    content_type="text/plain")
Пример #43
0
    def handle(self, *args, **options):
        username = options['username']
        name = options['name']
        if not username:
            username = options['email'].split('@')[0]
        if not name:
            name = options['email'].split('@')[0]

        # parse out the course into a coursekey
        if options['course']:
            try:
                course = CourseKey.from_string(options['course'])
            # if it's not a new-style course key, parse it from an old-style
            # course key
            except InvalidKeyError:
                course = SlashSeparatedCourseKey.from_deprecated_string(options['course'])

        post_data = {
            'username': username,
            'email': options['email'],
            'password': options['password'],
            'name': name,
            'honor_code': u'true',
            'terms_of_service': u'true',
        }
        # django.utils.translation.get_language() will be used to set the new
        # user's preferred language.  This line ensures that the result will
        # match this installation's default locale.  Otherwise, inside a
        # management command, it will always return "en-us".
        translation.activate(settings.LANGUAGE_CODE)
        try:
            user, profile, reg = _do_create_account(post_data)
            if options['staff']:
                user.is_staff = True
                user.save()
            reg.activate()
            reg.save()
            create_comments_service_user(user)
        except AccountValidationError as e:
            print e.message
            user = User.objects.get(email=options['email'])
        if options['course']:
            CourseEnrollment.enroll(user, course, mode=options['mode'])
        translation.deactivate()
Пример #44
0
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError("delete_course requires one or more arguments: <course_id> |commit|")

        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

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

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

        if query_yes_no("Deleting course {0}. Confirm?".format(course_key), default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
                delete_course_and_groups(course_key, commit)
    def handle(self, *args, **options):
        if not args:
            raise CommandError("Course id not specified")
        if len(args) > 1:
            raise CommandError("Only one course id may be specifiied")
        course_id = args[0]

        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                course_id)

        course = get_course(course_key)
        if not course:
            raise CommandError("Invalid course id: {}".format(course_id))

        if course.discussion_link:
            self.stdout.write(course.discussion_link)
Пример #46
0
def course_info_handler(request, course_key_string):
    """
    GET
        html: return html for editing the course info handouts and updates.
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):

        return render_to_response(
            'course_info.html',
            {
                'context_course': course_module,
                'updates_url': reverse_course_url('course_info_update_handler', course_key),
                'handouts_locator': course_key.make_usage_key('course_info', 'handouts'),
                'base_asset_url': StaticContent.get_base_url_path_for_course_assets(course_module.id)
            }
        )
    else:
        return HttpResponseBadRequest("Only supports html requests")
Пример #47
0
def course_info_handler(request, course_key_string):
    """
    GET
        html: return html for editing the course info handouts and updates.
    """
    course_key = CourseKey.from_string(course_key_string)
    course_module = _get_course_module(course_key, request.user)
    if "text/html" in request.META.get("HTTP_ACCEPT", "text/html"):

        return render_to_response(
            "course_info.html",
            {
                "context_course": course_module,
                "updates_url": reverse_course_url("course_info_update_handler", course_key),
                "handouts_locator": course_key.make_usage_key("course_info", "handouts"),
                "base_asset_url": StaticContent.get_base_url_path_for_course_assets(course_module.id),
            },
        )
    else:
        return HttpResponseBadRequest("Only supports html requests")
Пример #48
0
def import_status_handler(request, course_key_string, filename=None):
    """
    Returns an integer corresponding to the status of a file import. These are:

        0 : No status info found (import done or upload still in progress)
        1 : Extracting file
        2 : Validating.
        3 : Importing to mongo

    """
    course_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    try:
        session_status = request.session["import_status"]
        status = session_status[course_key_string + filename]
    except KeyError:
        status = 0

    return JsonResponse({"ImportStatus": status})
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 0:
            raise CommandError(
                "empty_asset_trashcan requires one or no arguments: |<course_id>|"
            )

        if len(args) == 1:
            try:
                course_key = CourseKey.from_string(args[0])
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(
                    args[0])

            course_ids = [course_key]
        else:
            course_ids = [
                course.id for course in modulestore('direct').get_courses()
            ]

        if query_yes_no("Emptying trashcan. Confirm?", default="no"):
            empty_asset_trashcan(course_ids)
Пример #50
0
def import_status_handler(request, course_key_string, filename=None):
    """
    Returns an integer corresponding to the status of a file import. These are:

        0 : No status info found (import done or upload still in progress)
        1 : Extracting file
        2 : Validating.
        3 : Importing to mongo

    """
    course_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    try:
        session_status = request.session["import_status"]
        status = session_status[course_key_string + filename]
    except KeyError:
        status = 0

    return JsonResponse({"ImportStatus": status})
Пример #51
0
    def handle(self, *args, **options):
        if not options['course']:
            raise CommandError(Command.course_option.help)

        try:
            course_key = CourseKey.from_string(options['course'])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                options['course'])

        course = get_course_by_id(course_key)

        print 'Warning: this command directly edits the list of course tabs in mongo.'
        print 'Tabs before any changes:'
        print_course(course)

        try:
            if options['delete']:
                if len(args) != 1:
                    raise CommandError(Command.delete_option.help)
                num = int(args[0])
                if query_yes_no('Deleting tab {0} Confirm?'.format(num),
                                default='no'):
                    tabs.primitive_delete(course,
                                          num - 1)  # -1 for 0-based indexing
            elif options['insert']:
                if len(args) != 3:
                    raise CommandError(Command.insert_option.help)
                num = int(args[0])
                tab_type = args[1]
                name = args[2]
                if query_yes_no(
                        'Inserting tab {0} "{1}" "{2}" Confirm?'.format(
                            num, tab_type, name),
                        default='no'):
                    tabs.primitive_insert(course, num - 1, tab_type,
                                          name)  # -1 as above
        except ValueError as e:
            # Cute: translate to CommandError so the CLI error prints nicely.
            raise CommandError(e)
Пример #52
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) != 2:
            raise CommandError(
                "export requires two arguments: <course id> <output path>")

        try:
            course_key = CourseKey.from_string(args[0])
        except InvalidKeyError:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                args[0])

        output_path = args[1]

        print("Exporting course id = {0} to {1}".format(
            course_key, output_path))

        root_dir = os.path.dirname(output_path)
        course_dir = os.path.splitext(os.path.basename(output_path))[0]

        export_to_xml(modulestore('direct'), contentstore(), course_key,
                      root_dir, course_dir, modulestore())