Ejemplo n.º 1
0
    def handle(self, *args, **options):
        source_key = SlashSeparatedCourseKey.from_deprecated_string(options['source_course'])
        dest_key = SlashSeparatedCourseKey.from_deprecated_string(options['dest_course'])

        source_students = User.objects.filter(
            courseenrollment__course_id=source_key
        )

        for user in source_students:
            if CourseEnrollment.is_enrolled(user, dest_key):
                # Un Enroll from source course but don't mess
                # with the enrollment in the destination course.
                CourseEnrollment.unenroll(user, source_key)
                print("Unenrolled {} from {}".format(user.username, source_key.to_deprecated_string()))
                msg = "Skipping {}, already enrolled in destination course {}"
                print(msg.format(user.username, dest_key.to_deprecated_string()))
                continue

            print("Moving {}.".format(user.username))
            # Find the old enrollment.
            enrollment = CourseEnrollment.objects.get(
                user=user,
                course_id=source_key
            )

            # Move the Student between the classes.
            mode = enrollment.mode
            old_is_active = enrollment.is_active
            CourseEnrollment.unenroll(user, source_key)
            new_enrollment = CourseEnrollment.enroll(user, dest_key, mode=mode)

            # Unenroll from the new coures if the user had unenrolled
            # form the old course.
            if not old_is_active:
                new_enrollment.update_enrollment(is_active=False)

            if mode == 'verified':
                try:
                    certificate_item = CertificateItem.objects.get(
                        course_id=source_key,
                        course_enrollment=enrollment
                    )
                except CertificateItem.DoesNotExist:
                    print("No certificate for {}".format(user))
                    continue

                certificate_item.course_id = dest_key
                certificate_item.course_enrollment = new_enrollment
                certificate_item.save()
Ejemplo n.º 2
0
def progress(request, course_id, student_id=None):
    """
    Wraps "_progress" with the manual_transaction context manager just in case
    there are unanticipated errors.
    """
    with grades.manual_transaction():
        return _progress(request, SlashSeparatedCourseKey.from_deprecated_string(course_id), student_id)
Ejemplo n.º 3
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)
    masq = setup_masquerade(request, staff_access)    # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course_key, 'course_info')

    context = {
        'request': request,
        'course_id': course_key.to_deprecated_string(),
        'cache': None,
        'course': course,
        'staff_access': staff_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
    }

    return render_to_response('courseware/info.html', context)
Ejemplo n.º 4
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)
Ejemplo n.º 5
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)
    def initdb(self, default):
        """
        Initialize the database and create one test course in it
        """
        # set the default modulestore
        self.options['stores']['default'] = self.options['stores'][default]
        self.store = MixedModuleStore(**self.options)
        self.addCleanup(self.store.close_all_connections)

        # convert to CourseKeys
        self.course_locations = {
            course_id:
            SlashSeparatedCourseKey.from_deprecated_string(course_id)
            for course_id in
            [self.MONGO_COURSEID, self.XML_COURSEID1, self.XML_COURSEID2]
        }
        # and then to the root UsageKey
        self.course_locations = {
            course_id: course_key.make_usage_key('course', course_key.run)
            for course_id, course_key in self.course_locations.iteritems()  # pylint: disable=maybe-no-member
        }
        self.fake_location = Location('foo', 'bar', 'slowly', 'vertical',
                                      'baz')
        self.import_chapter_location = self.course_locations[
            self.MONGO_COURSEID].replace(category='chapter', name='Overview')
        self.xml_chapter_location = self.course_locations[
            self.XML_COURSEID1].replace(category='chapter', name='Overview')
        # get Locators and set up the loc mapper if app is Locator based
        if default == 'split':
            self.fake_location = loc_mapper().translate_location(
                self.fake_location)

        self._create_course(
            default, self.course_locations[self.MONGO_COURSEID].course_key)
Ejemplo n.º 7
0
    def get(self, request, *args, **kwargs):
        """Shows logs of imports that happened as a result of a git import"""

        course_id = kwargs.get('course_id')
        if course_id:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)

        # Set mongodb defaults even if it isn't defined in settings
        mongo_db = {
            'host': 'localhost',
            'user': '',
            'password': '',
            'db': 'xlog',
        }

        # Allow overrides
        if hasattr(settings, 'MONGODB_LOG'):
            for config_item in ['host', 'user', 'password', 'db', ]:
                mongo_db[config_item] = settings.MONGODB_LOG.get(
                    config_item, mongo_db[config_item])

        mongouri = 'mongodb://{user}:{password}@{host}/{db}'.format(**mongo_db)

        error_msg = ''

        try:
            if mongo_db['user'] and mongo_db['password']:
                mdb = mongoengine.connect(mongo_db['db'], host=mongouri)
            else:
                mdb = mongoengine.connect(mongo_db['db'], host=mongo_db['host'])
        except mongoengine.connection.ConnectionError:
            log.exception('Unable to connect to mongodb to save log, '
                          'please check MONGODB_LOG settings.')

        if course_id is None:
            # Require staff if not going to specific course
            if not request.user.is_staff:
                raise Http404
            cilset = CourseImportLog.objects.all().order_by('-created')
        else:
            try:
                course = get_course_by_id(course_id)
            except Exception:  # pylint: disable=broad-except
                log.info('Cannot find course {0}'.format(course_id))
                raise Http404

            # Allow only course team, instructors, and staff
            if not (request.user.is_staff or
                    CourseInstructorRole(course.id).has_user(request.user) or
                    CourseStaffRole(course.id).has_user(request.user)):
                raise Http404
            log.debug('course_id={0}'.format(course_id))
            cilset = CourseImportLog.objects.filter(course_id=course_id).order_by('-created')
            log.debug('cilset length={0}'.format(len(cilset)))
        mdb.disconnect()
        context = {'cilset': cilset,
                   'course_id': course_id.to_deprecated_string() if course_id else None,
                   'error_msg': error_msg}

        return render_to_response(self.template_name, context)
Ejemplo n.º 8
0
def index(request, course_id, book_index, page=None):
    """
    Serve static image-based textbooks.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)

    book_index = int(book_index)
    if book_index < 0 or book_index >= len(course.textbooks):
        raise Http404("Invalid book index value: {0}".format(book_index))
    textbook = course.textbooks[book_index]
    table_of_contents = textbook.table_of_contents

    if page is None:
        page = textbook.start_page

    return render_to_response(
        'staticbook.html',
        {
            'book_index': book_index, 'page': int(page),
            'course': course,
            'book_url': textbook.book_url,
            'table_of_contents': table_of_contents,
            'start_page': textbook.start_page,
            'end_page': textbook.end_page,
            'staff_access': staff_access,
        },
    )
Ejemplo n.º 9
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Usage: unique_id_mapping %s" %
                               " ".join(("<%s>" % arg for arg in Command.args)))

        course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        # Generate the output filename from the course ID.
        # Change slashes to dashes first, and then append .csv extension.
        output_filename = course_key.to_deprecated_string().replace('/', '-') + ".csv"

        # Figure out which students are enrolled in the course
        students = User.objects.filter(courseenrollment__course_id=course_key)
        if len(students) == 0:
            self.stdout.write("No students enrolled in %s" % course_key.to_deprecated_string())
            return

        # Write mapping to output file in CSV format with a simple header
        try:
            with open(output_filename, 'wb') as output_file:
                csv_writer = csv.writer(output_file)
                csv_writer.writerow((
                    "User ID",
                    "Per-Student anonymized user ID",
                    "Per-course anonymized user id"
                ))
                for student in students:
                    csv_writer.writerow((
                        student.id,
                        anonymous_id_for_user(student, None),
                        anonymous_id_for_user(student, course_key)
                    ))
        except IOError:
            raise CommandError("Error writing to file: %s" % output_filename)
Ejemplo n.º 10
0
    def handle(self, *args, **options):
        """Handler for command."""

        task_number = options['task_number']

        if len(args) == 2:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
            usage_key = course_id.make_usage_key_from_deprecated_string(args[1])
        else:
            print self.help
            return

        try:
            course = get_course(course_id)
        except ValueError as err:
            print err
            return

        descriptor = modulestore().get_item(usage_key, depth=0)
        if descriptor is None:
            print "Location {0} not found in course".format(usage_key)
            return

        try:
            enrolled_students = CourseEnrollment.users_enrolled_in(course_id)
            print "Total students enrolled in {0}: {1}".format(course_id, enrolled_students.count())

            calculate_task_statistics(enrolled_students, course, usage_key, task_number)

        except KeyboardInterrupt:
            print "\nOperation Cancelled"
Ejemplo n.º 11
0
def section_problem_grade_distrib(request, course_id, section):
    """
    Creates a json with the grade distribution for the problems in the specified section.

    `request` django request

    `course_id` the course ID for the course interested in

    `section` The zero-based index of the section for the course

    Returns the format in dashboard_data.get_d3_section_grade_distrib

    If this is requested multiple times quickly for the same course, it is better to call all_problem_grade_distribution
    and pick out the sections of interest.
    """
    json = {}

    # Only instructor for this particular course can request this information
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if has_instructor_access_for_class(request.user, course_key):
        try:
            json = dashboard_data.get_d3_section_grade_distrib(course_key, section)
        except Exception as ex:  # pylint: disable=broad-except
            log.error('Generating metrics failed with exception: %s', ex)
            json = {'error': "error"}
    else:
        json = {'error': "Access Denied: User does not have access to this course's data"}

    return HttpResponse(simplejson.dumps(json), mimetype="application/json")
Ejemplo n.º 12
0
def all_sequential_open_distrib(request, course_id):
    """
    Creates a json with the open distribution for all the subsections in the course.

    `request` django request

    `course_id` the course ID for the course interested in

    Returns the format in dashboard_data.get_d3_sequential_open_distrib
    """

    json = {}

    # Only instructor for this particular course can request this information
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if has_instructor_access_for_class(request.user, course_key):
        try:
            json = dashboard_data.get_d3_sequential_open_distrib(course_key)
        except Exception as ex:  # pylint: disable=broad-except
            log.error('Generating metrics failed with exception: %s', ex)
            json = {'error': "error"}
    else:
        json = {'error': "Access Denied: User does not have access to this course's data"}

    return HttpResponse(simplejson.dumps(json), mimetype="application/json")
Ejemplo n.º 13
0
    def initdb(self, default):
        """
        Initialize the database and create one test course in it
        """
        # set the default modulestore
        self.options['stores']['default'] = self.options['stores'][default]
        self.store = MixedModuleStore(**self.options)
        self.addCleanup(self.store.close_all_connections)

        # convert to CourseKeys
        self.course_locations = {
            course_id: SlashSeparatedCourseKey.from_deprecated_string(course_id)
            for course_id in [self.MONGO_COURSEID, self.XML_COURSEID1, self.XML_COURSEID2]
        }
        # and then to the root UsageKey
        self.course_locations = {
            course_id: course_key.make_usage_key('course', course_key.run)
            for course_id, course_key in self.course_locations.iteritems()  # pylint: disable=maybe-no-member
        }
        self.fake_location = Location('foo', 'bar', 'slowly', 'vertical', 'baz')
        self.import_chapter_location = self.course_locations[self.MONGO_COURSEID].replace(
            category='chapter', name='Overview'
        )
        self.xml_chapter_location = self.course_locations[self.XML_COURSEID1].replace(
            category='chapter', name='Overview'
        )
        # get Locators and set up the loc mapper if app is Locator based
        if default == 'split':
            self.fake_location = loc_mapper().translate_location(self.fake_location)

        self._create_course(default, self.course_locations[self.MONGO_COURSEID].course_key)
Ejemplo n.º 14
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for the verification flow.
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if CourseEnrollment.enrollment_mode_for_user(request.user,
                                                 course_id) == 'verified':
        return redirect(reverse('dashboard'))

    upgrade = request.GET.get('upgrade', False)
    course = course_from_id(course_id)
    context = {
        "course_id":
        course_id.to_deprecated_string(),
        "course_modes_choose_url":
        reverse("course_modes_choose",
                kwargs={'course_id': course_id.to_deprecated_string()}),
        "verify_student_url":
        reverse('verify_student_verify',
                kwargs={'course_id': course_id.to_deprecated_string()}),
        "course_name":
        course.display_name_with_default,
        "course_org":
        course.display_org_with_default,
        "course_num":
        course.display_number_with_default,
        "is_not_active":
        not request.user.is_active,
        "upgrade":
        upgrade,
    }
    return render_to_response("verify_student/show_requirements.html", context)
Ejemplo n.º 15
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.build_absolute_uri())
        course_id = None
        if match:
            course_id = match.group('course_id')
            course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

        context = {}

        if course_id:
            context['course_id'] = course_id

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_key,
                    ).values_list('key', 'value')
                )
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(
            self.CONTEXT_NAME,
            context
        )
Ejemplo n.º 16
0
def add_course_to_cart(request, course_id):
    """
    Adds course specified by course_id to the cart.  The model function add_to_order does all the
    heavy lifting (logging, error checking, etc)
    """

    assert isinstance(course_id, basestring)
    if not request.user.is_authenticated():
        log.info("Anon user trying to add course {} to cart".format(course_id))
        return HttpResponseForbidden(
            _('You must be logged-in to add to a shopping cart'))
    cart = Order.get_cart_for_user(request.user)
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    # All logging from here handled by the model
    try:
        PaidCourseRegistration.add_to_order(cart, course_key)
    except CourseDoesNotExistException:
        return HttpResponseNotFound(
            _('The course you requested does not exist.'))
    except ItemAlreadyInCartException:
        return HttpResponseBadRequest(
            _('The course {0} is already in your cart.'.format(course_id)))
    except AlreadyEnrolledInCourseException:
        return HttpResponseBadRequest(
            _('You are already registered in course {0}.'.format(course_id)))
    return HttpResponse(_("Course added to cart."))
Ejemplo n.º 17
0
def spoc_gradebook(request, course_id):
    """
    Show the gradebook for this course:
    - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
    - Only displayed to course staff
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'staff', course_key, depth=None)

    enrolled_students = User.objects.filter(
        courseenrollment__course_id=course_key,
        courseenrollment__is_active=1
    ).order_by('username').select_related("profile")

    # possible extension: implement pagination to show to large courses

    student_info = [
        {
            'username': student.username,
            'id': student.id,
            'email': student.email,
            'grade_summary': student_grades(student, request, course),
            'realname': student.profile.name,
        }
        for student in enrolled_students
    ]

    return render_to_response('courseware/gradebook.html', {
        'students': student_info,
        'course': course,
        'course_id': course_key,
        # Checked above
        'staff_access': True,
        'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True),
    })
Ejemplo n.º 18
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
Ejemplo n.º 19
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 setUp(self):
        self.course_name = 'edX/toy/2012_Fall'

        # Create student account
        student = UserFactory.create()
        CourseEnrollmentFactory.create(
            user=student,
            course_id=SlashSeparatedCourseKey.from_deprecated_string(self.course_name)
        )
        self.client.login(username=student.username, password="******")

        try:
            # URL for dashboard
            self.url = reverse('dashboard')
        except NoReverseMatch:
            raise SkipTest("Skip this test if url cannot be found (ie running from CMS tests)")

        # URL for email settings modal
        self.email_modal_link = (
            ('<a href="#email-settings-modal" class="email-settings" rel="leanModal" '
             'data-course-id="{0}/{1}/{2}" data-course-number="{1}" '
             'data-optout="False">Email Settings</a>').format(
                 'edX',
                 'toy',
                 '2012_Fall'
             )
        )
Ejemplo n.º 21
0
    def handle(self, *args, **options):
        """Handler for command."""

        task_number = options['task_number']

        if len(args) == 2:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
            usage_key = course_id.make_usage_key_from_deprecated_string(
                args[1])
        else:
            print self.help
            return

        try:
            course = get_course(course_id)
        except ValueError as err:
            print err
            return

        descriptor = modulestore().get_item(usage_key, depth=0)
        if descriptor is None:
            print "Location {0} not found in course".format(usage_key)
            return

        try:
            enrolled_students = CourseEnrollment.users_enrolled_in(course_id)
            print "Total students enrolled in {0}: {1}".format(
                course_id, enrolled_students.count())

            calculate_task_statistics(enrolled_students, course, usage_key,
                                      task_number)

        except KeyboardInterrupt:
            print "\nOperation Cancelled"
Ejemplo n.º 22
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)
Ejemplo n.º 23
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))
Ejemplo n.º 24
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Usage: unique_id_mapping %s" % " ".join(
                ("<%s>" % arg for arg in Command.args)))

        course_key = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        # Generate the output filename from the course ID.
        # Change slashes to dashes first, and then append .csv extension.
        output_filename = course_key.to_deprecated_string().replace(
            '/', '-') + ".csv"

        # Figure out which students are enrolled in the course
        students = User.objects.filter(courseenrollment__course_id=course_key)
        if len(students) == 0:
            self.stdout.write("No students enrolled in %s" %
                              course_key.to_deprecated_string())
            return

        # Write mapping to output file in CSV format with a simple header
        try:
            with open(output_filename, 'wb') as output_file:
                csv_writer = csv.writer(output_file)
                csv_writer.writerow(
                    ("User ID", "Per-Student anonymized user ID",
                     "Per-course anonymized user id"))
                for student in students:
                    csv_writer.writerow(
                        (student.id, anonymous_id_for_user(student, None),
                         anonymous_id_for_user(student, course_key)))
        except IOError:
            raise CommandError("Error writing to file: %s" % output_filename)
Ejemplo n.º 25
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))
Ejemplo n.º 26
0
def request_certificate(request):
    """Request the on-demand creation of a certificate for some user, course.

    A request doesn't imply a guarantee that such a creation will take place.
    We intentionally use the same machinery as is used for doing certification
    at the end of a course run, so that we can be sure users get graded and
    then if and only if they pass, do they get a certificate issued.
    """
    if request.method == "POST":
        if request.user.is_authenticated():
            xqci = XQueueCertInterface()
            username = request.user.username
            student = User.objects.get(username=username)
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                request.POST.get('course_id'))
            course = modulestore().get_course(course_key, depth=2)

            status = certificate_status_for_student(student,
                                                    course_key)['status']
            if status in [
                    CertificateStatuses.unavailable,
                    CertificateStatuses.notpassing, CertificateStatuses.error
            ]:
                logger.info(
                    'Grading and certification requested for user {} in course {} via /request_certificate call'
                    .format(username, course_key))
                status = xqci.add_cert(student, course_key, course=course)
            return HttpResponse(json.dumps({'add_status': status}),
                                mimetype='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}),
                            mimetype='application/json')
Ejemplo n.º 27
0
def jump_to(request, course_id, location):
    """
    Show the page that contains a specific location.

    If the location is invalid or not in any class, return a 404.

    Otherwise, delegates to the index view to figure out whether this user
    has access, and what they should see.
    """
    try:
        course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        usage_key = course_key.make_usage_key_from_deprecated_string(location)
    except InvalidKeyError:
        raise Http404(u"Invalid course_key or usage_key")
    try:
        (course_key, chapter, section, position) = path_to_location(modulestore(), usage_key)
    except ItemNotFoundError:
        raise Http404(u"No data at this location: {0}".format(usage_key))
    except NoPathToItem:
        raise Http404(u"This location is not in any class: {0}".format(usage_key))

    # choose the appropriate view (and provide the necessary args) based on the
    # args provided by the redirect.
    # Rely on index to do all error handling and access control.
    if chapter is None:
        return redirect('courseware', course_id=course_key.to_deprecated_string())
    elif section is None:
        return redirect('courseware_chapter', course_id=course_key.to_deprecated_string(), chapter=chapter)
    elif position is None:
        return redirect('courseware_section', course_id=course_key.to_deprecated_string(), chapter=chapter, section=section)
    else:
        return redirect('courseware_position', course_id=course_key.to_deprecated_string(), chapter=chapter, section=section, position=position)
Ejemplo n.º 28
0
    def test_dump_course_structure(self):
        args = [TEST_COURSE_ID]
        kwargs = {'modulestore': 'default'}
        output = self.call_command('dump_course_structure', *args, **kwargs)

        dump = json.loads(output)

        # check that all elements in the course structure have metadata,
        # but not inherited metadata:
        for element in dump.itervalues():
            self.assertIn('metadata', element)
            self.assertIn('children', element)
            self.assertIn('category', element)
            self.assertNotIn('inherited_metadata', element)

        # Check a few elements in the course dump
        test_course_key = SlashSeparatedCourseKey.from_deprecated_string(TEST_COURSE_ID)
        parent_id = test_course_key.make_usage_key('chapter', 'Overview').to_deprecated_string()
        self.assertEqual(dump[parent_id]['category'], 'chapter')
        self.assertEqual(len(dump[parent_id]['children']), 3)

        child_id = dump[parent_id]['children'][1]
        self.assertEqual(dump[child_id]['category'], 'videosequence')
        self.assertEqual(len(dump[child_id]['children']), 2)

        video_id = test_course_key.make_usage_key('video', 'Welcome').to_deprecated_string()
        self.assertEqual(dump[video_id]['category'], 'video')
        self.assertEqual(len(dump[video_id]['metadata']), 4)
        self.assertIn('youtube_id_1_0', dump[video_id]['metadata'])

        # Check if there are the right number of elements

        self.assertEqual(len(dump), 16)
Ejemplo n.º 29
0
def static_tab(request, course_id, tab_slug):
    """
    Display the courses tab with the given name.

    Assumes the course_id is in a valid format.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)

    tab = CourseTabList.get_tab_by_slug(course.tabs, tab_slug)
    if tab is None:
        raise Http404

    contents = get_static_tab_contents(
        request,
        course,
        tab
    )
    if contents is None:
        raise Http404

    return render_to_response('courseware/static_tab.html', {
        'course': course,
        'tab': tab,
        'tab_contents': contents,
    })
Ejemplo n.º 30
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("course_id not specified")

        # Get the modulestore

        try:
            name = options['modulestore']
            store = modulestore(name)
        except KeyError:
            raise CommandError("Unknown modulestore {}".format(name))

        # Get the course data

        try:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
        except InvalidKeyError:
            raise CommandError("Invalid course_id")

        course = store.get_course(course_id)
        if course is None:
            raise CommandError("Invalid course_id")

        # precompute inherited metadata at the course level, if needed:
        if options['inherited']:
            compute_inherited_metadata(course)

        # Convert course data to dictionary and dump it as JSON to stdout

        info = dump_module(course,
                           inherited=options['inherited'],
                           defaults=options['inherited_defaults'])

        return json.dumps(info, indent=2, sort_keys=True)
Ejemplo n.º 31
0
def get_anon_ids(request, course_id):  # pylint: disable=W0613
    """
    Respond with 2-column CSV output of user-id, anonymized-user-id
    """
    # TODO: the User.objects query and CSV generation here could be
    # centralized into analytics. Currently analytics has similar functionality
    # but not quite what's needed.
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    def csv_response(filename, header, rows):
        """Returns a CSV http response for the given header and rows (excel/utf-8)."""
        response = HttpResponse(mimetype='text/csv')
        response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
        writer = csv.writer(response, dialect='excel', quotechar='"', quoting=csv.QUOTE_ALL)
        # In practice, there should not be non-ascii data in this query,
        # but trying to do the right thing anyway.
        encoded = [unicode(s).encode('utf-8') for s in header]
        writer.writerow(encoded)
        for row in rows:
            encoded = [unicode(s).encode('utf-8') for s in row]
            writer.writerow(encoded)
        return response

    students = User.objects.filter(
        courseenrollment__course_id=course_id,
    ).order_by('id')
    header = ['User ID', 'Anonymized user ID', 'Course Specific Anonymized user ID']
    rows = [[s.id, unique_id_for_user(s), anonymous_id_for_user(s, course_id)] for s in students]
    return csv_response(course_id.to_deprecated_string().replace('/', '-') + '-anon-ids.csv', header, rows)
Ejemplo n.º 32
0
def section_problem_grade_distrib(request, course_id, section):
    """
    Creates a json with the grade distribution for the problems in the specified section.

    `request` django request

    `course_id` the course ID for the course interested in

    `section` The zero-based index of the section for the course

    Returns the format in dashboard_data.get_d3_section_grade_distrib

    If this is requested multiple times quickly for the same course, it is better to call all_problem_grade_distribution
    and pick out the sections of interest.
    """
    json = {}

    # Only instructor for this particular course can request this information
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if has_instructor_access_for_class(request.user, course_key):
        try:
            json = dashboard_data.get_d3_section_grade_distrib(
                course_key, section)
        except Exception as ex:  # pylint: disable=broad-except
            log.error('Generating metrics failed with exception: %s', ex)
            json = {'error': "error"}
    else:
        json = {
            'error':
            "Access Denied: User does not have access to this course's data"
        }

    return HttpResponse(simplejson.dumps(json), mimetype="application/json")
Ejemplo n.º 33
0
def all_problem_grade_distribution(request, course_id):
    """
    Creates a json with the grade distribution for all the problems in the course.

    `Request` django request

    `course_id` the course ID for the course interested in

    Returns the format in dashboard_data.get_d3_problem_grade_distrib
    """
    json = {}

    # Only instructor for this particular course can request this information
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if has_instructor_access_for_class(request.user, course_key):
        try:
            json = dashboard_data.get_d3_problem_grade_distrib(course_key)
        except Exception as ex:  # pylint: disable=broad-except
            log.error('Generating metrics failed with exception: %s', ex)
            json = {'error': "error"}
    else:
        json = {
            'error':
            "Access Denied: User does not have access to this course's data"
        }

    return HttpResponse(simplejson.dumps(json), mimetype="application/json")
Ejemplo n.º 34
0
def send_email(request, course_id):
    """
    Send an email to self, staff, or everyone involved in a course.
    Query Parameters:
    - 'send_to' specifies what group the email should be sent to
       Options are defined by the CourseEmail model in
       lms/djangoapps/bulk_email/models.py
    - 'subject' specifies email's subject
    - 'message' specifies email's content
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    if not bulk_email_is_enabled_for_course(course_id):
        return HttpResponseForbidden("Email is not enabled for this course.")

    send_to = request.POST.get("send_to")
    subject = request.POST.get("subject")
    message = request.POST.get("message")

    # Create the CourseEmail object.  This is saved immediately, so that
    # any transaction that has been pending up to this point will also be
    # committed.
    email = CourseEmail.create(course_id, request.user, send_to, subject,
                               message)

    # Submit the task, so that the correct InstructorTask object gets created (for monitoring purposes)
    instructor_task.api.submit_bulk_course_email(request, course_id, email.id)  # pylint: disable=E1101

    response_payload = {
        'course_id': course_id.to_deprecated_string(),
        'success': True,
    }
    return JsonResponse(response_payload)
Ejemplo n.º 35
0
def add_cohort(request, course_key):
    """
    Return json of dict:
    {'success': True,
     'cohort': {'id': id,
                'name': name}}

                or

    {'success': False,
     'msg': error_msg} if there's an error
    """
    # this is a string when we get it here
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_key)

    get_course_with_access(request.user, 'staff', course_key)

    name = request.POST.get("name")
    if not name:
        return json_http_response({'success': False,
                                'msg': "No name specified"})

    try:
        cohort = cohorts.add_cohort(course_key, name)
    except ValueError as err:
        return json_http_response({'success': False,
                                'msg': str(err)})

    return json_http_response({'success': 'True',
                            'cohort': {
                                'id': cohort.id,
                                'name': cohort.name
                                }})
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("course_id not specified")

        # Get the modulestore

        try:
            name = options["modulestore"]
            store = modulestore(name)
        except KeyError:
            raise CommandError("Unknown modulestore {}".format(name))

        # Get the course data

        try:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
        except InvalidKeyError:
            raise CommandError("Invalid course_id")

        course = store.get_course(course_id)
        if course is None:
            raise CommandError("Invalid course_id")

        # precompute inherited metadata at the course level, if needed:
        if options["inherited"]:
            compute_inherited_metadata(course)

        # Convert course data to dictionary and dump it as JSON to stdout

        info = dump_module(course, inherited=options["inherited"], defaults=options["inherited_defaults"])

        return json.dumps(info, indent=2, sort_keys=True)
Ejemplo n.º 37
0
def send_email(request, course_id):
    """
    Send an email to self, staff, or everyone involved in a course.
    Query Parameters:
    - 'send_to' specifies what group the email should be sent to
       Options are defined by the CourseEmail model in
       lms/djangoapps/bulk_email/models.py
    - 'subject' specifies email's subject
    - 'message' specifies email's content
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    if not bulk_email_is_enabled_for_course(course_id):
        return HttpResponseForbidden("Email is not enabled for this course.")

    send_to = request.POST.get("send_to")
    subject = request.POST.get("subject")
    message = request.POST.get("message")

    # Create the CourseEmail object.  This is saved immediately, so that
    # any transaction that has been pending up to this point will also be
    # committed.
    email = CourseEmail.create(course_id, request.user, send_to, subject, message)

    # Submit the task, so that the correct InstructorTask object gets created (for monitoring purposes)
    instructor_task.api.submit_bulk_course_email(request, course_id, email.id)  # pylint: disable=E1101

    response_payload = {
        'course_id': course_id.to_deprecated_string(),
        'success': True,
    }
    return JsonResponse(response_payload)
Ejemplo n.º 38
0
def index(request, course_id, book_index, page=None):
    """
    Serve static image-based textbooks.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)

    book_index = int(book_index)
    if book_index < 0 or book_index >= len(course.textbooks):
        raise Http404("Invalid book index value: {0}".format(book_index))
    textbook = course.textbooks[book_index]
    table_of_contents = textbook.table_of_contents

    if page is None:
        page = textbook.start_page

    return render_to_response(
        'staticbook.html',
        {
            'book_index': book_index,
            'page': int(page),
            'course': course,
            'book_url': textbook.book_url,
            'table_of_contents': table_of_contents,
            'start_page': textbook.start_page,
            'end_page': textbook.end_page,
            'staff_access': staff_access,
        },
    )
Ejemplo n.º 39
0
    def handle(self, *args, **options):

        dry_run = options['dry_run']
        task_number = options['task_number']

        if len(args) == 4:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
            location = course_id.make_usage_key_from_deprecated_string(args[1])
            students_ids = [line.strip() for line in open(args[2])]
            hostname = args[3]
        else:
            print self.help
            return

        try:
            course = get_course(course_id)
        except ValueError as err:
            print err
            return

        descriptor = modulestore().get_item(location, depth=0)
        if descriptor is None:
            print "Location not found in course"
            return

        if dry_run:
            print "Doing a dry run."

        students = User.objects.filter(id__in=students_ids).order_by('username')
        print "Number of students: {0}".format(students.count())

        for student in students:
            post_submission_for_student(student, course, location, task_number, dry_run=dry_run, hostname=hostname)
Ejemplo n.º 40
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
Ejemplo n.º 41
0
    def process_request(self, request):
        """
        Add a user's tags to the tracking event context.
        """
        match = COURSE_REGEX.match(request.build_absolute_uri())
        course_id = None
        if match:
            course_id = match.group('course_id')
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                course_id)

        context = {}

        if course_id:
            context['course_id'] = course_id

            if request.user.is_authenticated():
                context['course_user_tags'] = dict(
                    UserCourseTag.objects.filter(
                        user=request.user.pk,
                        course_id=course_key,
                    ).values_list('key', 'value'))
            else:
                context['course_user_tags'] = {}

        tracker.get_tracker().enter_context(self.CONTEXT_NAME, context)
Ejemplo n.º 42
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
Ejemplo n.º 43
0
def remove_user_from_cohort(request, course_key, cohort_id):
    """
    Expects 'username': username in POST data.

    Return json dict of:

    {'success': True} or
    {'success': False,
     'msg': error_msg}
    """
    # this is a string when we get it here
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_key)
    get_course_with_access(request.user, 'staff', course_key)

    username = request.POST.get('username')
    if username is None:
        return json_http_response({'success': False,
                                   'msg': 'No username specified'})

    cohort = cohorts.get_cohort_by_id(course_key, cohort_id)
    try:
        user = User.objects.get(username=username)
        cohort.users.remove(user)
        return json_http_response({'success': True})
    except User.DoesNotExist:
        log.debug('no user')
        return json_http_response({'success': False,
                                   'msg': "No user '{0}'".format(username)})
Ejemplo n.º 44
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()
Ejemplo n.º 45
0
def show_unit_extensions(request, course_id):
    """
    Shows all of the students which have due date extensions for the given unit.
    """
    course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
    unit = find_unit(course, request.GET.get('url'))
    return JsonResponse(dump_module_extensions(course, unit))
    def setUp(self):
        self.course_name = 'edX/toy/2012_Fall'

        # Create student account
        student = UserFactory.create()
        CourseEnrollmentFactory.create(
            user=student,
            course_id=SlashSeparatedCourseKey.from_deprecated_string(
                self.course_name))
        self.client.login(username=student.username, password="******")

        try:
            # URL for dashboard
            self.url = reverse('dashboard')
        except NoReverseMatch:
            raise SkipTest(
                "Skip this test if url cannot be found (ie running from CMS tests)"
            )

        # URL for email settings modal
        self.email_modal_link = ((
            '<a href="#email-settings-modal" class="email-settings" rel="leanModal" '
            'data-course-id="{0}/{1}/{2}" data-course-number="{1}" '
            'data-optout="False">Email Settings</a>').format(
                'edX', 'toy', '2012_Fall'))
Ejemplo n.º 47
0
def get_student_progress_url(request, course_id):
    """
    Get the progress url of a student.
    Limited to staff access.

    Takes query paremeter unique_student_identifier and if the student exists
    returns e.g. {
        'progress_url': '/../...'
    }
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    user = get_student_from_identifier(
        request.GET.get('unique_student_identifier'))

    progress_url = reverse('student_progress',
                           kwargs={
                               'course_id': course_id.to_deprecated_string(),
                               'student_id': user.id
                           })

    response_payload = {
        'course_id': course_id.to_deprecated_string(),
        'progress_url': progress_url,
    }
    return JsonResponse(response_payload)
Ejemplo n.º 48
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    if microsite.get_value('ENABLE_MKTG_SITE',
                           settings.FEATURES.get('ENABLE_MKTG_SITE', False)):
        raise Http404
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'see_exists', course_key)
    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, 'staff', course)
    studio_url = get_studio_url(course_key, 'settings/details')

    if has_access(request.user, 'load', course):
        course_target = reverse('info',
                                args=[course.id.to_deprecated_string()])
    else:
        course_target = reverse('about_course',
                                args=[course.id.to_deprecated_string()])

    show_courseware_link = (has_access(request.user, 'load', course)
                            or settings.FEATURES.get('ENABLE_LMS_MIGRATION'))

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if (settings.FEATURES.get('ENABLE_SHOPPING_CART')
            and settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
        registration_price = CourseMode.min_course_price_for_currency(
            course_key, settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(
                cart, course_key)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse('register_user'),
            course_id=course.id.to_deprecated_string())

    # see if we have already filled up all allowed enrollments
    is_course_full = CourseEnrollment.is_course_full(course)

    return render_to_response(
        'courseware/course_about.html', {
            'course': course,
            'staff_access': staff_access,
            'studio_url': studio_url,
            'registered': registered,
            'course_target': course_target,
            'registration_price': registration_price,
            'in_cart': in_cart,
            'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
            'show_courseware_link': show_courseware_link,
            'is_course_full': is_course_full
        })
Ejemplo n.º 49
0
def show_unit_extensions(request, course_id):
    """
    Shows all of the students which have due date extensions for the given unit.
    """
    course = get_course_by_id(
        SlashSeparatedCourseKey.from_deprecated_string(course_id))
    unit = find_unit(course, request.GET.get('url'))
    return JsonResponse(dump_module_extensions(course, unit))
Ejemplo n.º 50
0
class MidcourseReverificationWindowFactory(DjangoModelFactory):
    """ Creates a generic MidcourseReverificationWindow. """
    FACTORY_FOR = MidcourseReverificationWindow

    course_id = SlashSeparatedCourseKey.from_deprecated_string(u'MITx/999/Robot_Super_Course')
    # By default this factory creates a window that is currently open
    start_date = datetime.now(pytz.UTC) - timedelta(days=100)
    end_date = datetime.now(pytz.UTC) + timedelta(days=100)
Ejemplo n.º 51
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)