示例#1
0
 def test_update_creator_group(self):
     with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
         self.assertFalse(is_user_in_creator_group(self.user))
         update_course_creator_group(self.admin, self.user, True)
         self.assertTrue(is_user_in_creator_group(self.user))
         update_course_creator_group(self.admin, self.user, False)
         self.assertFalse(is_user_in_creator_group(self.user))
 def test_update_creator_group(self):
     with mock.patch.dict('django.conf.settings.MITX_FEATURES',
                          {"ENABLE_CREATOR_GROUP": True}):
         self.assertFalse(is_user_in_creator_group(self.user))
         update_course_creator_group(self.admin, self.user, True)
         self.assertTrue(is_user_in_creator_group(self.user))
         update_course_creator_group(self.admin, self.user, False)
         self.assertFalse(is_user_in_creator_group(self.user))
示例#3
0
    def test_creator_group_enabled_but_empty(self):
        """ Tests creator group feature on, but group empty. """
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            self.assertFalse(is_user_in_creator_group(self.user))

            # Make user staff. This will cause is_user_in_creator_group to return True.
            self.user.is_staff = True
            self.assertTrue(is_user_in_creator_group(self.user))
示例#4
0
    def test_creator_group_enabled_but_empty(self):
        """ Tests creator group feature on, but group empty. """
        with mock.patch.dict('django.conf.settings.FEATURES',
                             {"ENABLE_CREATOR_GROUP": True}):
            self.assertFalse(is_user_in_creator_group(self.user))

            # Make user staff. This will cause is_user_in_creator_group to return True.
            self.user.is_staff = True
            self.assertTrue(is_user_in_creator_group(self.user))
示例#5
0
    def test_creator_group_enabled_nonempty(self):
        """ Tests creator group feature on, user added. """
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            self.assertTrue(add_user_to_creator_group(self.admin, self.user))
            self.assertTrue(is_user_in_creator_group(self.user))

            # check that a user who has not been added to the group still returns false
            user_not_added = User.objects.create_user('testuser2', '*****@*****.**', 'foo2')
            self.assertFalse(is_user_in_creator_group(user_not_added))

            # remove first user from the group and verify that is_user_in_creator_group now returns false
            remove_user_from_creator_group(self.admin, self.user)
            self.assertFalse(is_user_in_creator_group(self.user))
示例#6
0
    def test_add_granted(self):
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            # Calling add_user_with_status_granted impacts is_user_in_course_group_role.
            self.assertFalse(is_user_in_creator_group(self.user))

            add_user_with_status_granted(self.admin, self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            # Calling add again will be a no-op (even if state is different).
            add_user_with_status_unrequested(self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            self.assertTrue(is_user_in_creator_group(self.user))
    def test_add_granted(self):
        with mock.patch.dict('django.conf.settings.MITX_FEATURES',
                             {"ENABLE_CREATOR_GROUP": True}):
            # Calling add_user_with_status_granted impacts is_user_in_course_group_role.
            self.assertFalse(is_user_in_creator_group(self.user))

            add_user_with_status_granted(self.admin, self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            # Calling add again will be a no-op (even if state is different).
            add_user_with_status_unrequested(self.user)
            self.assertEqual('granted', get_course_creator_status(self.user))

            self.assertTrue(is_user_in_creator_group(self.user))
    def test_grant_creator_access(self):
        """
        Test for _grant_instructors_creator_access.
        """
        [creator1, staff1] = self.create_course(1)
        [creator2, staff2] = self.create_course(2)
        with mock.patch.dict('django.conf.settings.MITX_FEATURES',
                             {"ENABLE_CREATOR_GROUP": True}):
            # Initially no creators.
            self.assertFalse(is_user_in_creator_group(creator1))
            self.assertFalse(is_user_in_creator_group(creator2))
            self.assertFalse(is_user_in_creator_group(staff1))
            self.assertFalse(is_user_in_creator_group(staff2))

            admin = User.objects.create_user('populate_creators_command',
                                             '*****@*****.**',
                                             'foo')
            admin.is_staff = True
            _grant_instructors_creator_access(admin)

            # Now instructors only are creators.
            self.assertTrue(is_user_in_creator_group(creator1))
            self.assertTrue(is_user_in_creator_group(creator2))
            self.assertFalse(is_user_in_creator_group(staff1))
            self.assertFalse(is_user_in_creator_group(staff2))
示例#9
0
    def test_change_status(self):
        """
        Tests that updates to state impact the creator group maintained in authz.py.
        """
        def change_state(state, is_creator):
            """ Helper method for changing state """
            self.table_entry.state = state
            self.creator_admin.save_model(self.request, self.table_entry, None, True)
            self.assertEqual(is_creator, is_user_in_creator_group(self.user))

        with mock.patch.dict('django.conf.settings.MITX_FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            # User is initially unrequested.
            self.assertFalse(is_user_in_creator_group(self.user))

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.DENIED, False)

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.PENDING, False)

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.UNREQUESTED, False)
示例#10
0
    def test_creator_group_enabled_nonempty(self):
        """ Tests creator group feature on, user added. """
        with mock.patch.dict('django.conf.settings.FEATURES',
                             {"ENABLE_CREATOR_GROUP": True}):
            self.assertTrue(add_user_to_creator_group(self.admin, self.user))
            self.assertTrue(is_user_in_creator_group(self.user))

            # check that a user who has not been added to the group still returns false
            user_not_added = User.objects.create_user('testuser2',
                                                      '*****@*****.**',
                                                      'foo2')
            self.assertFalse(is_user_in_creator_group(user_not_added))

            # remove first user from the group and verify that is_user_in_creator_group now returns false
            remove_user_from_creator_group(self.admin, self.user)
            self.assertFalse(is_user_in_creator_group(self.user))
示例#11
0
def create_new_course(request):

    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    # This logic is repeated in xmodule/modulestore/tests/factories.py
    # so if you change anything here, you need to also change it there.
    # TODO: write a test that creates two courses, one with the factory and
    # the other with this method, then compare them to make sure they are
    # equivalent.
    template = Location(request.POST['template'])
    org = request.POST.get('org')
    number = request.POST.get('number')
    display_name = request.POST.get('display_name')

    try:
        dest_location = Location('i4x', org, number, 'course', Location.clean(display_name))
    except InvalidLocationError as error:
        return HttpResponse(json.dumps({'ErrMsg': "Unable to create course '" +
                                        display_name + "'.\n\n" + error.message}))

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass

    if existing_course is not None:
        return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with this name.'}))

    course_search_location = ['i4x', dest_location.org, dest_location.course, 'course', None]
    courses = modulestore().get_items(course_search_location)

    if len(courses) > 0:
        return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with the same organization and course number.'}))

    new_course = modulestore('direct').clone_item(template, dest_location)

    # clone a default 'about' module as well

    about_template_location = Location(['i4x', 'edx', 'templates', 'about', 'overview'])
    dest_about_location = dest_location._replace(category='about', name='overview')
    modulestore('direct').clone_item(about_template_location, dest_about_location)

    if display_name is not None:
        new_course.display_name = display_name

    # set a default start date to now
    new_course.start = datetime.datetime.now(UTC())

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    return HttpResponse(json.dumps({'id': new_course.location.url()}))
示例#12
0
    def test_course_creation_disabled(self):
        """ Tests that the COURSE_CREATION_DISABLED flag overrides course creator group settings. """
        with mock.patch.dict('django.conf.settings.FEATURES',
                             {'DISABLE_COURSE_CREATION': True, "ENABLE_CREATOR_GROUP": True}):
            # Add user to creator group.
            self.assertTrue(add_user_to_creator_group(self.admin, self.user))

            # DISABLE_COURSE_CREATION overrides (user is not marked as staff).
            self.assertFalse(is_user_in_creator_group(self.user))

            # Mark as staff. Now is_user_in_creator_group returns true.
            self.user.is_staff = True
            self.assertTrue(is_user_in_creator_group(self.user))

            # Remove user from creator group. is_user_in_creator_group still returns true because is_staff=True
            remove_user_from_creator_group(self.admin, self.user)
            self.assertTrue(is_user_in_creator_group(self.user))
示例#13
0
def create_new_course(request):
    """
    Create a new course
    """
    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    org = request.POST.get("org")
    number = request.POST.get("number")
    display_name = request.POST.get("display_name")

    try:
        dest_location = Location("i4x", org, number, "course", Location.clean(display_name))
    except InvalidLocationError as error:
        return JsonResponse(
            {"ErrMsg": "Unable to create course '{name}'.\n\n{err}".format(name=display_name, err=error.message)}
        )

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore("direct").get_item(dest_location)
    except ItemNotFoundError:
        pass
    if existing_course is not None:
        return JsonResponse({"ErrMsg": "There is already a course defined with this name."})

    course_search_location = ["i4x", dest_location.org, dest_location.course, "course", None]
    courses = modulestore().get_items(course_search_location)
    if len(courses) > 0:
        return JsonResponse(
            {"ErrMsg": "There is already a course defined with the same organization and course number."}
        )

    # instantiate the CourseDescriptor and then persist it
    # note: no system to pass
    if display_name is None:
        metadata = {}
    else:
        metadata = {"display_name": display_name}
    modulestore("direct").create_and_save_xmodule(dest_location, metadata=metadata)
    new_course = modulestore("direct").get_item(dest_location)

    # clone a default 'about' overview module as well
    dest_about_location = dest_location.replace(category="about", name="overview")
    overview_template = AboutDescriptor.get_template("overview.yaml")
    modulestore("direct").create_and_save_xmodule(
        dest_about_location, system=new_course.system, definition_data=overview_template.get("data")
    )

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    return JsonResponse({"id": new_course.location.url()})
示例#14
0
    def test_course_creation_disabled(self):
        """ Tests that the COURSE_CREATION_DISABLED flag overrides course creator group settings. """
        with mock.patch.dict('django.conf.settings.FEATURES', {
                'DISABLE_COURSE_CREATION': True,
                "ENABLE_CREATOR_GROUP": True
        }):
            # Add user to creator group.
            self.assertTrue(add_user_to_creator_group(self.admin, self.user))

            # DISABLE_COURSE_CREATION overrides (user is not marked as staff).
            self.assertFalse(is_user_in_creator_group(self.user))

            # Mark as staff. Now is_user_in_creator_group returns true.
            self.user.is_staff = True
            self.assertTrue(is_user_in_creator_group(self.user))

            # Remove user from creator group. is_user_in_creator_group still returns true because is_staff=True
            remove_user_from_creator_group(self.admin, self.user)
            self.assertTrue(is_user_in_creator_group(self.user))
示例#15
0
    def test_change_status(self, email_user):
        """
        Tests that updates to state impact the creator group maintained in authz.py and that e-mails are sent.
        """
        STUDIO_REQUEST_EMAIL = '*****@*****.**'

        def change_state(state, is_creator):
            """ Helper method for changing state """
            self.table_entry.state = state
            self.creator_admin.save_model(self.request, self.table_entry, None, True)
            self.assertEqual(is_creator, is_user_in_creator_group(self.user))

            context = {'studio_request_email': STUDIO_REQUEST_EMAIL}
            if state == CourseCreator.GRANTED:
                template = 'emails/course_creator_granted.txt'
            elif state == CourseCreator.DENIED:
                template = 'emails/course_creator_denied.txt'
            else:
                template = 'emails/course_creator_revoked.txt'
            email_user.assert_called_with(
                mock_render_to_string('emails/course_creator_subject.txt', context),
                mock_render_to_string(template, context),
                STUDIO_REQUEST_EMAIL
            )

        with mock.patch.dict(
            'django.conf.settings.MITX_FEATURES',
            {
                "ENABLE_CREATOR_GROUP": True,
                "STUDIO_REQUEST_EMAIL": STUDIO_REQUEST_EMAIL
            }
        ):

            # User is initially unrequested.
            self.assertFalse(is_user_in_creator_group(self.user))

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.DENIED, False)

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.PENDING, False)

            change_state(CourseCreator.GRANTED, True)

            change_state(CourseCreator.UNREQUESTED, False)
示例#16
0
        def change_state_and_verify_email(state, is_creator):
            """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """
            self._change_state(state)
            self.assertEqual(is_creator, is_user_in_creator_group(self.user))

            context = {'studio_request_email': self.studio_request_email}
            if state == CourseCreator.GRANTED:
                template = 'emails/course_creator_granted.txt'
            elif state == CourseCreator.DENIED:
                template = 'emails/course_creator_denied.txt'
            else:
                template = 'emails/course_creator_revoked.txt'
            email_user.assert_called_with(
                mock_render_to_string('emails/course_creator_subject.txt', context),
                mock_render_to_string(template, context),
                self.studio_request_email
            )
示例#17
0
 def change_state(state, is_creator):
     """ Helper method for changing state """
     self.table_entry.state = state
     self.creator_admin.save_model(self.request, self.table_entry, None, True)
     self.assertEqual(is_creator, is_user_in_creator_group(self.user))
     
     context = {'studio_request_email': STUDIO_REQUEST_EMAIL}
     if state == CourseCreator.GRANTED:
         template = 'emails/course_creator_granted.txt'
     elif state == CourseCreator.DENIED:
         template = 'emails/course_creator_denied.txt'
     else:
         template = 'emails/course_creator_revoked.txt'
     email_user.assert_called_with(
         mock_render_to_string('emails/course_creator_subject.txt', context),
         mock_render_to_string(template, context),
         STUDIO_REQUEST_EMAIL
     )
示例#18
0
    def test_grant_creator_access(self):
        """
        Test for _grant_instructors_creator_access.
        """
        [creator1, staff1] = self.create_course(1)
        [creator2, staff2] = self.create_course(2)
        with mock.patch.dict('django.conf.settings.MITX_FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            # Initially no creators.
            self.assertFalse(is_user_in_creator_group(creator1))
            self.assertFalse(is_user_in_creator_group(creator2))
            self.assertFalse(is_user_in_creator_group(staff1))
            self.assertFalse(is_user_in_creator_group(staff2))

            admin = User.objects.create_user('populate_creators_command', '*****@*****.**', 'foo')
            admin.is_staff = True
            _grant_instructors_creator_access(admin)

            # Now instructors only are creators.
            self.assertTrue(is_user_in_creator_group(creator1))
            self.assertTrue(is_user_in_creator_group(creator2))
            self.assertFalse(is_user_in_creator_group(staff1))
            self.assertFalse(is_user_in_creator_group(staff2))
示例#19
0
    def test_change_status(self, email_user):
        """
        Tests that updates to state impact the creator group maintained in authz.py and that e-mails are sent.
        """

        def change_state_and_verify_email(state, is_creator):
            """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """
            self._change_state(state)
            self.assertEqual(is_creator, is_user_in_creator_group(self.user))

            context = {'studio_request_email': self.studio_request_email}
            if state == CourseCreator.GRANTED:
                template = 'emails/course_creator_granted.txt'
            elif state == CourseCreator.DENIED:
                template = 'emails/course_creator_denied.txt'
            else:
                template = 'emails/course_creator_revoked.txt'
            email_user.assert_called_with(
                mock_render_to_string('emails/course_creator_subject.txt', context),
                mock_render_to_string(template, context),
                self.studio_request_email
            )

        with mock.patch.dict('django.conf.settings.MITX_FEATURES', self.enable_creator_group_patch):

            # User is initially unrequested.
            self.assertFalse(is_user_in_creator_group(self.user))

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.DENIED, False)

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.PENDING, False)

            change_state_and_verify_email(CourseCreator.GRANTED, True)

            change_state_and_verify_email(CourseCreator.UNREQUESTED, False)

            change_state_and_verify_email(CourseCreator.DENIED, False)
示例#20
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    org = request.json.get('org')
    number = request.json.get('number')
    display_name = request.json.get('display_name')
    run = request.json.get('run')

    try:
        dest_location = Location('i4x', org, number, 'course', run)
    except InvalidLocationError as error:
        return JsonResponse({
            "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
                name=display_name, err=error.message)})

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass
    if existing_course is not None:
        return JsonResponse({
            'ErrMsg': _('There is already a course defined with the same '
                'organization, course number, and course run. Please '
                'change either organization or course number to be '
                'unique.'),
            'OrgErrMsg': _('Please change either the organization or '
                'course number so that it is unique.'),
            'CourseErrMsg': _('Please change either the organization or '
                'course number so that it is unique.'),
        })

    # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this
    # file for new locators. get_items should accept a query rather than requiring it be a legal location
    course_search_location = bson.son.SON({
        '_id.tag': 'i4x',
        # cannot pass regex to Location constructor; thus this hack
        '_id.org': re.compile('^{}$'.format(dest_location.org), re.IGNORECASE),
        '_id.course': re.compile('^{}$'.format(dest_location.course), re.IGNORECASE),
        '_id.category': 'course',
    })
    courses = modulestore().collection.find(course_search_location, fields=('_id'))
    if courses.count() > 0:
        return JsonResponse({
            'ErrMsg': _('There is already a course defined with the same '
                'organization and course number. Please '
                'change at least one field to be unique.'),
            'OrgErrMsg': _('Please change either the organization or '
                'course number so that it is unique.'),
            'CourseErrMsg': _('Please change either the organization or '
                'course number so that it is unique.'),
        })

    # instantiate the CourseDescriptor and then persist it
    # note: no system to pass
    if display_name is None:
        metadata = {}
    else:
        metadata = {'display_name': display_name}
    modulestore('direct').create_and_save_xmodule(
        dest_location,
        metadata=metadata
    )
    new_course = modulestore('direct').get_item(dest_location)

    # clone a default 'about' overview module as well
    dest_about_location = dest_location.replace(
        category='about',
        name='overview'
    )
    overview_template = AboutDescriptor.get_template('overview.yaml')
    modulestore('direct').create_and_save_xmodule(
        dest_about_location,
        system=new_course.system,
        definition_data=overview_template.get('data')
    )

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    # auto-enroll the course creator in the course so that "View Live" will
    # work.
    CourseEnrollment.enroll(request.user, new_course.location.course_id)

    new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True)
    return JsonResponse({'url': new_location.url_reverse("course/", "")})
示例#21
0
def create_new_course(request):

    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    # This logic is repeated in xmodule/modulestore/tests/factories.py
    # so if you change anything here, you need to also change it there.
    # TODO: write a test that creates two courses, one with the factory and
    # the other with this method, then compare them to make sure they are
    # equivalent.
    template = Location(request.POST['template'])
    org = request.POST.get('org')
    number = request.POST.get('number')
    display_name = request.POST.get('display_name')

    try:
        dest_location = Location('i4x', org, number, 'course',
                                 Location.clean(display_name))
    except InvalidLocationError as error:
        return HttpResponse(
            json.dumps({
                'ErrMsg':
                "Unable to create course '" + display_name + "'.\n\n" +
                error.message
            }))

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass

    if existing_course is not None:
        return HttpResponse(
            json.dumps({
                'ErrMsg':
                'There is already a course defined with this name.'
            }))

    course_search_location = [
        'i4x', dest_location.org, dest_location.course, 'course', None
    ]
    courses = modulestore().get_items(course_search_location)

    if len(courses) > 0:
        return HttpResponse(
            json.dumps({
                'ErrMsg':
                'There is already a course defined with the same organization and course number.'
            }))

    new_course = modulestore('direct').clone_item(template, dest_location)

    # clone a default 'about' module as well

    about_template_location = Location(
        ['i4x', 'edx', 'templates', 'about', 'overview'])
    dest_about_location = dest_location._replace(category='about',
                                                 name='overview')
    modulestore('direct').clone_item(about_template_location,
                                     dest_about_location)

    if display_name is not None:
        new_course.display_name = display_name

    # set a default start date to now
    new_course.start = datetime.datetime.now(UTC())

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    return HttpResponse(json.dumps({'id': new_course.location.url()}))
示例#22
0
 def change_state(state, is_creator):
     """ Helper method for changing state """
     self.table_entry.state = state
     self.creator_admin.save_model(self.request, self.table_entry, None, True)
     self.assertEqual(is_creator, is_user_in_creator_group(self.user))
示例#23
0
def create_new_course(request):
    """
    Create a new course
    """
    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    org = request.POST.get('org')
    number = request.POST.get('number')
    display_name = request.POST.get('display_name')
    run = request.POST.get('run')

    try:
        dest_location = Location('i4x', org, number, 'course', run)
    except InvalidLocationError as error:
        return JsonResponse({
            "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
                name=display_name, err=error.message)})

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass
    if existing_course is not None:
        return JsonResponse({
                'ErrMsg': _('There is already a course defined with the same '
                    'organization, course number, and course run. Please '
                    'change either organization or course number to be '
                    'unique.'),
                'OrgErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
                'CourseErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
        })

    course_search_location = ['i4x', dest_location.org, dest_location.course,
            'course', None
    ]
    courses = modulestore().get_items(course_search_location)
    if len(courses) > 0:
        return JsonResponse({
                'ErrMsg': _('There is already a course defined with the same '
                    'organization and course number. Please '
                    'change at least one field to be unique.'),
                'OrgErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
                'CourseErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
        })

    # instantiate the CourseDescriptor and then persist it
    # note: no system to pass
    if display_name is None:
        metadata = {}
    else:
        metadata = {'display_name': display_name}
    modulestore('direct').create_and_save_xmodule(
            dest_location,
            metadata=metadata
    )
    new_course = modulestore('direct').get_item(dest_location)

    # clone a default 'about' overview module as well
    dest_about_location = dest_location.replace(
            category='about',
            name='overview'
    )
    overview_template = AboutDescriptor.get_template('overview.yaml')
    modulestore('direct').create_and_save_xmodule(
        dest_about_location,
        system=new_course.system,
        definition_data=overview_template.get('data')
    )

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    # auto-enroll the course creator in the course so that "View Live" will
    # work.
    CourseEnrollment.enroll(request.user, new_course.location.course_id)

    return JsonResponse({'id': new_course.location.url()})
示例#24
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    org = request.json.get('org')
    number = request.json.get('number')
    display_name = request.json.get('display_name')
    run = request.json.get('run')

    try:
        dest_location = Location('i4x', org, number, 'course', run)
    except InvalidLocationError as error:
        return JsonResponse({
            "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
                name=display_name, err=error.message)})

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass
    if existing_course is not None:
        return JsonResponse({
            'ErrMsg': _(
                'There is already a course defined with the same '
                'organization, course number, and course run. Please '
                'change either organization or course number to be '
                'unique.'
            ),
            'OrgErrMsg': _(
                'Please change either the organization or '
                'course number so that it is unique.'
            ),
            'CourseErrMsg': _(
                'Please change either the organization or '
                'course number so that it is unique.'
            ),
        })

    # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this
    # file for new locators. get_items should accept a query rather than requiring it be a legal location
    course_search_location = bson.son.SON({
        '_id.tag': 'i4x',
        # cannot pass regex to Location constructor; thus this hack
        '_id.org': re.compile('^{}$'.format(dest_location.org), re.IGNORECASE),
        '_id.course': re.compile('^{}$'.format(dest_location.course), re.IGNORECASE),
        '_id.category': 'course',
    })
    courses = modulestore().collection.find(course_search_location, fields=('_id'))
    if courses.count() > 0:
        return JsonResponse({
            'ErrMsg': _(
                'There is already a course defined with the same '
                'organization and course number. Please '
                'change at least one field to be unique.'),
            'OrgErrMsg': _(
                'Please change either the organization or '
                'course number so that it is unique.'),
            'CourseErrMsg': _(
                'Please change either the organization or '
                'course number so that it is unique.'),
        })

    # instantiate the CourseDescriptor and then persist it
    # note: no system to pass
    if display_name is None:
        metadata = {}
    else:
        metadata = {'display_name': display_name}
    modulestore('direct').create_and_save_xmodule(
        dest_location,
        metadata=metadata
    )
    new_course = modulestore('direct').get_item(dest_location)

    # clone a default 'about' overview module as well
    dest_about_location = dest_location.replace(
        category='about',
        name='overview'
    )
    overview_template = AboutDescriptor.get_template('overview.yaml')
    modulestore('direct').create_and_save_xmodule(
        dest_about_location,
        system=new_course.system,
        definition_data=overview_template.get('data')
    )

    initialize_course_tabs(new_course)

    new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True)
    create_all_course_groups(request.user, new_location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    # auto-enroll the course creator in the course so that "View Live" will
    # work.
    CourseEnrollment.enroll(request.user, new_course.location.course_id)

    return JsonResponse({'url': new_location.url_reverse("course/", "")})
示例#25
0
def create_new_course(request):
    """
    Create a new course
    """
    if not is_user_in_creator_group(request.user):
        raise PermissionDenied()

    org = request.POST.get('org')
    number = request.POST.get('number')
    display_name = request.POST.get('display_name')
    run = request.POST.get('run')

    try:
        dest_location = Location('i4x', org, number, 'course', run)
    except InvalidLocationError as error:
        return JsonResponse({
            "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
                name=display_name, err=error.message)})

    # see if the course already exists
    existing_course = None
    try:
        existing_course = modulestore('direct').get_item(dest_location)
    except ItemNotFoundError:
        pass
    if existing_course is not None:
        return JsonResponse({
                'ErrMsg': _('There is already a course defined with the same '
                    'organization, course number, and course run. Please '
                    'change either organization or course number to be '
                    'unique.'),
                'OrgErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
                'CourseErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
        })

    course_search_location = ['i4x', dest_location.org, dest_location.course,
            'course', None
    ]
    courses = modulestore().get_items(course_search_location)
    if len(courses) > 0:
        return JsonResponse({
                'ErrMsg': _('There is already a course defined with the same '
                    'organization and course number. Please '
                    'change at least one field to be unique.'),
                'OrgErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
                'CourseErrMsg': _('Please change either the organization or '
                    'course number so that it is unique.'),
        })

    # instantiate the CourseDescriptor and then persist it
    # note: no system to pass
    if display_name is None:
        metadata = {}
    else:
        metadata = {'display_name': display_name}
    modulestore('direct').create_and_save_xmodule(
            dest_location,
            metadata=metadata
    )
    new_course = modulestore('direct').get_item(dest_location)

    # clone a default 'about' overview module as well
    dest_about_location = dest_location.replace(
            category='about',
            name='overview'
    )
    overview_template = AboutDescriptor.get_template('overview.yaml')
    modulestore('direct').create_and_save_xmodule(
        dest_about_location,
        system=new_course.system,
        definition_data=overview_template.get('data')
    )

    initialize_course_tabs(new_course)

    create_all_course_groups(request.user, new_course.location)

    # seed the forums
    seed_permissions_roles(new_course.location.course_id)

    # auto-enroll the course creator in the course so that "View Live" will
    # work.
    CourseEnrollment.enroll(request.user, new_course.location.course_id)

    return JsonResponse({'id': new_course.location.url()})
示例#26
0
 def test_creator_group_not_enabled(self):
     """
     Tests that is_user_in_creator_group always returns True if ENABLE_CREATOR_GROUP
     and DISABLE_COURSE_CREATION are both not turned on.
     """
     self.assertTrue(is_user_in_creator_group(self.user))
示例#27
0
 def test_creator_group_not_enabled(self):
     """
     Tests that is_user_in_creator_group always returns True if ENABLE_CREATOR_GROUP
     and DISABLE_COURSE_CREATION are both not turned on.
     """
     self.assertTrue(is_user_in_creator_group(self.user))