Example #1
0
    def setUp(self):
        super(UpdateThreadUnicodeTestCase, self).setUp()

        self.course = CourseFactory.create()
        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
Example #2
0
def import_single_course(filename):
    print >> sys.stderr, 'IMPORTING course:', filename
    course_id, course_run = _filename_to_id_and_run(filename)

    course_full_id = 'course-v1:Microsoft+{id}+{run}'.format(id=course_id,
                                                             run=course_run)

    course_xml_dir = path.join(
        XML_EXTRACT_DIR, '{id}-{run}'.format(id=course_id, run=course_run))
    mkdir(course_xml_dir)

    subprocess.call(['tar', '-xzf', filename, '-C', course_xml_dir])

    _fix_library_source_bug(course_xml_dir)

    print >> sys.stderr, 'IMPORTING course:', course_full_id
    course_items = import_course_from_xml(
        store=MOD_STORE,
        user_id=ModuleStoreEnum.UserID.mgmt_command,
        data_dir=DATA_DIR,
        source_dirs=[path.join(course_xml_dir,
                               'course')],  # Open edX needs `course` dir
        load_error_modules=False,
        static_content_store=contentstore(),
        verbose=True,
        do_import_static=True,
        target_id=CourseKey.from_string(course_full_id),
        create_if_not_present=True,
    )

    for course in course_items:
        course_id = course.id
        if not are_permissions_roles_seeded(course_id):
            print >> sys.stderr, 'Seeding forum roles for course', course_id
            seed_permissions_roles(course_id)
Example #3
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) == 0:
            raise CommandError("import requires at least one argument: <data directory> [--nostatic] [<course dir>...]")

        data_dir = args[0]
        do_import_static = not (options.get('nostatic', False))
        if len(args) > 1:
            course_dirs = args[1:]
        else:
            course_dirs = None
        self.stdout.write("Importing.  Data_dir={data}, course_dirs={courses}\n".format(
            data=data_dir,
            courses=course_dirs,
            dis=do_import_static))
        try:
            mstore = modulestore('direct')
        except KeyError:
            self.stdout.write('Unable to load direct modulestore, trying '
                              'default\n')
            mstore = modulestore('default')

        _, course_items = import_from_xml(
            mstore, data_dir, course_dirs, load_error_modules=False,
            static_content_store=contentstore(), verbose=True,
            do_import_static=do_import_static,
            create_new_course_if_not_present=True,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write('Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #4
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) == 0:
            raise CommandError("import requires at least one argument: <data directory> [--nostatic] [<course dir>...]")

        data_dir = args[0]
        do_import_static = not options.get('nostatic', False)
        if len(args) > 1:
            source_dirs = args[1:]
        else:
            source_dirs = None
        self.stdout.write("Importing.  Data_dir={data}, source_dirs={courses}\n".format(
            data=data_dir,
            courses=source_dirs,
        ))
        mstore = modulestore()

        course_items = import_course_from_xml(
            mstore, ModuleStoreEnum.UserID.mgmt_command, data_dir, source_dirs, load_error_modules=False,
            static_content_store=contentstore(), verbose=True,
            do_import_static=do_import_static,
            create_if_not_present=True,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write('Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #5
0
 def setUp(self):
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     self.enrollment = CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     self.other_user = UserFactory.create(username="******")
     CourseEnrollmentFactory(user=self.other_user, course_id=self.course.id)
Example #6
0
    def setUp(self):
        super(CohortedContentTestCase, self).setUp()

        self.course = CourseFactory.create(
            discussion_topics={
                "cohorted topic": {"id": "cohorted_topic"},
                "non-cohorted topic": {"id": "non_cohorted_topic"},
            },
            cohort_config={
                "cohorted": True,
                "cohorted_discussions": ["cohorted_topic"]
            }
        )
        self.student_cohort = CourseUserGroup.objects.create(
            name="student_cohort",
            course_id=self.course.id,
            group_type=CourseUserGroup.COHORT
        )
        self.moderator_cohort = CourseUserGroup.objects.create(
            name="moderator_cohort",
            course_id=self.course.id,
            group_type=CourseUserGroup.COHORT
        )

        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        self.moderator = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
        CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
        self.moderator.roles.add(Role.objects.get(name="Moderator", course_id=self.course.id))
        self.student_cohort.users.add(self.student)
        self.moderator_cohort.users.add(self.moderator)
Example #7
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) == 0:
            raise CommandError("import requires at least one argument: <data directory> [--nostatic] [<course dir>...]")

        data_dir = args[0]
        do_import_static = not (options.get('nostatic', False))
        if len(args) > 1:
            course_dirs = args[1:]
        else:
            course_dirs = None
        self.stdout.write("Importing.  Data_dir={data}, course_dirs={courses}\n".format(
            data=data_dir,
            courses=course_dirs,
            dis=do_import_static))
        try:
            mstore = modulestore('direct')
        except KeyError:
            self.stdout.write('Unable to load direct modulestore, trying '
                              'default\n')
            mstore = modulestore('default')

        _, course_items = import_from_xml(
            mstore, data_dir, course_dirs, load_error_modules=False,
            static_content_store=contentstore(), verbose=True,
            do_import_static=do_import_static
        )

        for module in course_items:
            course_id = module.location.course_id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write('Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #8
0
    def test_set_roles(self, course_id, course_key):
        seed_permissions_roles(course_key)
        course_roles = dict((r.name, r) for r in Role.objects.filter(course_id=course_key))
        self.assertEqual(len(course_roles), 5)  # sanity check

        # Student role is assigned by default on course enrollment.
        self._auto_auth({'username': '******', 'course_id': course_id})
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(len(user_roles), 1)
        self.assertEqual(user_roles[0], course_roles[FORUM_ROLE_STUDENT])

        self.client.logout()
        self._auto_auth({'username': '******', 'course_id': course_id, 'roles': 'Moderator'})
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR]]))

        # check multiple roles work.
        self.client.logout()
        self._auto_auth({
            'username': '******', 'course_id': course_id,
            'roles': '{},{}'.format(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR)
        })
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR],
                course_roles[FORUM_ROLE_ADMINISTRATOR]]))
Example #9
0
    def setUp(self):
        super(CohortedTestCase, self).setUp()

        self.course = CourseFactory.create(
            cohort_config={
                "cohorted": True,
                "cohorted_discussions": ["cohorted_topic"]
            })
        self.student_cohort = CohortFactory.create(name="student_cohort",
                                                   course_id=self.course.id)
        self.moderator_cohort = CohortFactory.create(name="moderator_cohort",
                                                     course_id=self.course.id)
        self.course.discussion_topics["cohorted topic"] = {
            "id": "cohorted_topic"
        }
        self.course.discussion_topics["non-cohorted topic"] = {
            "id": "non_cohorted_topic"
        }
        self.store.update_item(self.course, self.user.id)

        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        self.moderator = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
        CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
        self.moderator.roles.add(
            Role.objects.get(name="Moderator", course_id=self.course.id))
        self.student_cohort.users.add(self.student)
        self.moderator_cohort.users.add(self.moderator)
Example #10
0
 def setUp(self):
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     self.enrollment = CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     self.other_user = UserFactory.create(username="******")
     CourseEnrollmentFactory(user=self.other_user, course_id=self.course.id)
Example #11
0
    def test_set_roles(self):
        seed_permissions_roles(self.course_key)
        course_roles = dict((r.name, r) for r in Role.objects.filter(course_id=self.course_key))
        self.assertEqual(len(course_roles), 4)  # sanity check

        # Student role is assigned by default on course enrollment.
        self._auto_auth(username="******", course_id=self.course_id)
        user = User.objects.get(username="******")
        user_roles = user.roles.all()
        self.assertEqual(len(user_roles), 1)
        self.assertEqual(user_roles[0], course_roles[FORUM_ROLE_STUDENT])

        self._auto_auth(username="******", course_id=self.course_id, roles="Moderator")
        user = User.objects.get(username="******")
        user_roles = user.roles.all()
        self.assertEqual(set(user_roles), set([course_roles[FORUM_ROLE_STUDENT], course_roles[FORUM_ROLE_MODERATOR]]))

        # check multiple roles work.
        self._auto_auth(
            username="******",
            course_id=self.course_id,
            roles="{},{}".format(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR),
        )
        user = User.objects.get(username="******")
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set(
                [
                    course_roles[FORUM_ROLE_STUDENT],
                    course_roles[FORUM_ROLE_MODERATOR],
                    course_roles[FORUM_ROLE_ADMINISTRATOR],
                ]
            ),
        )
Example #12
0
    def handle(self, *args, **options):
        data_dir = options['data_directory']
        do_import_static = not options['nostatic']
        source_dirs = options['course_dirs']
        if len(source_dirs) == 0:
            source_dirs = None

        self.stdout.write(
            "Importing.  Data_dir={data}, source_dirs={courses}\n".format(
                data=data_dir,
                courses=source_dirs,
            ))
        mstore = modulestore()

        course_items = import_course_from_xml(
            mstore,
            ModuleStoreEnum.UserID.mgmt_command,
            data_dir,
            source_dirs,
            load_error_modules=False,
            static_content_store=contentstore(),
            verbose=True,
            do_import_static=do_import_static,
            create_if_not_present=True,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write(
                    'Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #13
0
    def test_set_roles(self, course_id, course_key):
        seed_permissions_roles(course_key)
        course_roles = dict((r.name, r) for r in Role.objects.filter(course_id=course_key))
        self.assertEqual(len(course_roles), 4)  # sanity check

        # Student role is assigned by default on course enrollment.
        self._auto_auth(username='******', course_id=course_id)
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(len(user_roles), 1)
        self.assertEqual(user_roles[0], course_roles[FORUM_ROLE_STUDENT])

        self._auto_auth(username='******', course_id=course_id, roles='Moderator')
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR]]))

        # check multiple roles work.
        self._auto_auth(username='******', course_id=course_id,
                        roles='{},{}'.format(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR))
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR],
                course_roles[FORUM_ROLE_ADMINISTRATOR]]))
    def test_set_roles(self):

        course_id = "edX/Test101/2014_Spring"
        seed_permissions_roles(course_id)
        course_roles = dict((r.name, r) for r in Role.objects.filter(course_id=course_id))
        self.assertEqual(len(course_roles), 4)  # sanity check

        # Student role is assigned by default on course enrollment.
        self._auto_auth(username='******', course_id=course_id)
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(len(user_roles), 1)
        self.assertEqual(user_roles[0], course_roles[FORUM_ROLE_STUDENT])

        self._auto_auth(username='******', course_id=course_id, roles='Moderator')
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR]]))

        # check multiple roles work.
        self._auto_auth(username='******', course_id=course_id,
                        roles='{},{}'.format(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR))
        user = User.objects.get(username='******')
        user_roles = user.roles.all()
        self.assertEqual(
            set(user_roles),
            set([course_roles[FORUM_ROLE_STUDENT],
                course_roles[FORUM_ROLE_MODERATOR],
                course_roles[FORUM_ROLE_ADMINISTRATOR]]))
Example #15
0
    def setUp(self):
        super(CohortedTestCase, self).setUp()

        self.course = CourseFactory.create(
            cohort_config={
                "cohorted": True,
                "cohorted_discussions": ["cohorted_topic"]
            }
        )
        self.student_cohort = CohortFactory.create(
            name="student_cohort",
            course_id=self.course.id
        )
        self.moderator_cohort = CohortFactory.create(
            name="moderator_cohort",
            course_id=self.course.id
        )
        self.course.discussion_topics["cohorted topic"] = {"id": "cohorted_topic"}
        self.course.discussion_topics["non-cohorted topic"] = {"id": "non_cohorted_topic"}
        self.store.update_item(self.course, self.user.id)

        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        self.moderator = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
        CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
        self.moderator.roles.add(Role.objects.get(name="Moderator", course_id=self.course.id))
        self.student_cohort.users.add(self.student)
        self.moderator_cohort.users.add(self.moderator)
Example #16
0
    def setUp(self):
        super(CreateSubCommentUnicodeTestCase, self).setUp()

        self.course = CourseFactory.create()
        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
Example #17
0
def create_new_course(request):

    if settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False) and not request.user.is_staff:
        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()}))
Example #18
0
def create_new_course(request):

    if settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False) and not request.user.is_staff:
        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()}))
Example #19
0
    def handle(self, *args, **options):
        if len(args) == 0:
            raise CommandError("Please provide a course id")
        if len(args) > 1:
            raise CommandError("Too many arguments")
        course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])

        seed_permissions_roles(course_id)
    def handle(self, *args, **options):
        if len(args) == 0:
            raise CommandError("Please provide a course id")
        if len(args) > 1:
            raise CommandError("Too many arguments")
        course_id = args[0]

        seed_permissions_roles(course_id)
Example #21
0
 def setUp(self):
     super(ForumEventTestCase, self).setUp()
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     self.student.roles.add(Role.objects.get(name="Student", course_id=self.course.id))
     CourseAccessRoleFactory(course_id=self.course.id, user=self.student, role='Wizard')
Example #22
0
 def setUp(self):
     super(ForumEventTestCase, self).setUp()
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     self.student.roles.add(Role.objects.get(name="Student", course_id=self.course.id))
     CourseAccessRoleFactory(course_id=self.course.id, user=self.student, role='Wizard')
Example #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")

    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()})
Example #24
0
 def setUp(self):
     super(ViewPermissionsTestCase, self).setUp()
     self.password = "******"
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create(password=self.password)
     self.moderator = UserFactory.create(password=self.password)
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
     self.moderator.roles.add(Role.objects.get(name="Moderator", course_id=self.course.id))
Example #25
0
 def setUp(self):
     super(ViewPermissionsTestCase, self).setUp()
     self.password = "******"
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create(password=self.password)
     self.moderator = UserFactory.create(password=self.password)
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
     CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
     self.moderator.roles.add(Role.objects.get(name="Moderator", course_id=self.course.id))
Example #26
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            'staff':
            AdminFactory.create(password=self.test_password),
            'course_staff':
            StaffFactory.create(course_key=self.test_course_1.id,
                                password=self.test_password)
        }
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******',
                                       courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username='******')
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA,
                                             course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users['community_ta'])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2],
            username='******')

        # 'solar team' is intentionally lower case to test case insensitivity in name ordering
        self.test_team_1 = CourseTeamFactory.create(
            name=u'sólar team',
            course_id=self.test_course_1.id,
            topic_id='topic_0')
        self.test_team_2 = CourseTeamFactory.create(
            name='Wind Team', course_id=self.test_course_1.id)
        self.test_team_3 = CourseTeamFactory.create(
            name='Nuclear Team', course_id=self.test_course_1.id)
        self.test_team_4 = CourseTeamFactory.create(
            name='Coal Team', course_id=self.test_course_1.id, is_active=False)
        self.test_team_5 = CourseTeamFactory.create(
            name='Another Team', course_id=self.test_course_2.id)

        for user, course in [
            ('staff', self.test_course_1),
            ('course_staff', self.test_course_1),
        ]:
            CourseEnrollment.enroll(self.users[user],
                                    course.id,
                                    check_access=True)

        self.test_team_1.add_user(self.users['student_enrolled'])
        self.test_team_3.add_user(
            self.users['student_enrolled_both_courses_other_team'])
        self.test_team_5.add_user(
            self.users['student_enrolled_both_courses_other_team'])
Example #27
0
def initialize_permissions(course_key, user_who_created_course):
    """
    Initializes a new course by enrolling the course creator as a student,
    and initializing Forum by seeding its permissions and assigning default roles.
    """
    # seed the forums
    seed_permissions_roles(course_key)

    # auto-enroll the course creator in the course so that "View Live" will work.
    CourseEnrollment.enroll(user_who_created_course, course_key)

    # set default forum roles (assign 'Student' role)
    assign_default_role(course_key, user_who_created_course)
Example #28
0
def initialize_permissions(course_key, user_who_created_course):
    """
    Initializes a new course by enrolling the course creator as a student,
    and initializing Forum by seeding its permissions and assigning default roles.
    """
    # seed the forums
    seed_permissions_roles(course_key)

    # auto-enroll the course creator in the course so that "View Live" will work.
    CourseEnrollment.enroll(user_who_created_course, course_key)

    # set default forum roles (assign 'Student' role)
    assign_default_role(course_key, user_who_created_course)
Example #29
0
    def setUp(self):
        super(CohortedTestCase, self).setUp()

        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        self.moderator = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
        CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
        self.moderator.roles.add(
            Role.objects.get(name="Moderator", course_id=self.course.id))
        self.student_cohort = CohortFactory.create(name="student_cohort",
                                                   course_id=self.course.id,
                                                   users=[self.student])
        self.moderator_cohort = CohortFactory.create(name="moderator_cohort",
                                                     course_id=self.course.id,
                                                     users=[self.moderator])
Example #30
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            'staff': AdminFactory.create(password=self.test_password),
            'course_staff': StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password)
        }
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******', courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username='******')
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users['community_ta'])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2],
            username='******'
        )

        # 'solar team' is intentionally lower case to test case insensitivity in name ordering
        self.test_team_1 = CourseTeamFactory.create(
            name=u'sólar team',
            course_id=self.test_course_1.id,
            topic_id='topic_0'
        )
        self.test_team_2 = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id)
        self.test_team_3 = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id)
        self.test_team_4 = CourseTeamFactory.create(name='Coal Team', course_id=self.test_course_1.id, is_active=False)
        self.test_team_5 = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id)

        for user, course in [
                ('staff', self.test_course_1),
                ('course_staff', self.test_course_1),
        ]:
            CourseEnrollment.enroll(
                self.users[user], course.id, check_access=True
            )

        self.test_team_1.add_user(self.users['student_enrolled'])
        self.test_team_3.add_user(self.users['student_enrolled_both_courses_other_team'])
        self.test_team_5.add_user(self.users['student_enrolled_both_courses_other_team'])
Example #31
0
    def handle(self, *args, **options):
        data_dir = options['data_directory']
        source_dirs = options['course_dirs']
        if len(source_dirs) == 0:
            source_dirs = None
        do_import_static = not options.get('nostatic', False)
        # If the static content is not skipped, the python lib should be imported regardless
        # of the 'nopythonlib' flag.
        do_import_python_lib = do_import_static or not options.get(
            'nopythonlib', False)
        python_lib_filename = options.get('python_lib_filename')

        output = ("Importing...\n"
                  "    data_dir={data}, source_dirs={courses}\n"
                  "    Importing static content? {import_static}\n"
                  "    Importing python lib? {import_python_lib}").format(
                      data=data_dir,
                      courses=source_dirs,
                      import_static=do_import_static,
                      import_python_lib=do_import_python_lib)
        self.stdout.write(output)
        mstore = modulestore()

        course_items = import_course_from_xml(
            mstore,
            ModuleStoreEnum.UserID.mgmt_command,
            data_dir,
            source_dirs,
            load_error_modules=False,
            static_content_store=contentstore(),
            verbose=True,
            do_import_static=do_import_static,
            do_import_python_lib=do_import_python_lib,
            create_if_not_present=True,
            python_lib_filename=python_lib_filename,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write(
                    'Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #32
0
    def setUp(self):
        super(CohortedTestCase, self).setUp()

        seed_permissions_roles(self.course.id)
        self.student = UserFactory.create()
        self.moderator = UserFactory.create()
        CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
        CourseEnrollmentFactory(user=self.moderator, course_id=self.course.id)
        self.moderator.roles.add(Role.objects.get(name="Moderator", course_id=self.course.id))
        self.student_cohort = CohortFactory.create(
            name="student_cohort",
            course_id=self.course.id,
            users=[self.student]
        )
        self.moderator_cohort = CohortFactory.create(
            name="moderator_cohort",
            course_id=self.course.id,
            users=[self.moderator]
        )
Example #33
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) == 0:
            raise CommandError(
                "import requires at least one argument: <data directory> [--nostatic] [<course dir>...]"
            )

        data_dir = args[0]
        do_import_static = not (options.get('nostatic', False))
        if len(args) > 1:
            source_dirs = args[1:]
        else:
            source_dirs = None
        self.stdout.write(
            "Importing.  Data_dir={data}, source_dirs={courses}\n".format(
                data=data_dir,
                courses=source_dirs,
            ))
        mstore = modulestore()

        course_items = import_course_from_xml(
            mstore,
            ModuleStoreEnum.UserID.mgmt_command,
            data_dir,
            source_dirs,
            load_error_modules=False,
            static_content_store=contentstore(),
            verbose=True,
            do_import_static=do_import_static,
            create_if_not_present=True,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write(
                    'Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #34
0
    def handle(self, *args, **options):
        data_dir = options['data_directory']
        source_dirs = options['course_dirs']
        if len(source_dirs) == 0:
            source_dirs = None
        do_import_static = not options.get('nostatic', False)
        # If the static content is not skipped, the python lib should be imported regardless
        # of the 'nopythonlib' flag.
        do_import_python_lib = do_import_static or not options.get('nopythonlib', False)
        python_lib_filename = options.get('python_lib_filename')

        output = (
            "Importing...\n"
            "    data_dir={data}, source_dirs={courses}\n"
            "    Importing static content? {import_static}\n"
            "    Importing python lib? {import_python_lib}"
        ).format(
            data=data_dir,
            courses=source_dirs,
            import_static=do_import_static,
            import_python_lib=do_import_python_lib
        )
        self.stdout.write(output)
        mstore = modulestore()

        course_items = import_course_from_xml(
            mstore, ModuleStoreEnum.UserID.mgmt_command, data_dir, source_dirs, load_error_modules=False,
            static_content_store=contentstore(), verbose=True,
            do_import_static=do_import_static, do_import_python_lib=do_import_python_lib,
            create_if_not_present=True,
            python_lib_filename=python_lib_filename,
        )

        for course in course_items:
            course_id = course.id
            if not are_permissions_roles_seeded(course_id):
                self.stdout.write('Seeding forum roles for course {0}\n'.format(course_id))
                seed_permissions_roles(course_id)
Example #35
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not auth.has_access(request.user, CourseCreatorRole()):
        raise PermissionDenied()

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

    # allow/disable unicode characters in course_id according to settings
    if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'):
        if _has_non_ascii_characters(org) or _has_non_ascii_characters(
                number) or _has_non_ascii_characters(run):
            return JsonResponse(
                {
                    'error':
                    _('Special characters not allowed in organization, course number, and course run.'
                      )
                },
                status=400)

    try:
        dest_location = Location(u'i4x', org, number, u'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
        # pylint: disable=E1101
        '_id.org':
        re.compile(u'^{}$'.format(dest_location.org),
                   re.IGNORECASE | re.UNICODE),
        # pylint: disable=E1101
        '_id.course':
        re.compile(u'^{}$'.format(dest_location.course),
                   re.IGNORECASE | re.UNICODE),
        '_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}

    # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for existing xml courses this
    # cannot be changed in CourseDescriptor.
    wiki_slug = "{0}.{1}.{2}".format(dest_location.org, dest_location.course,
                                     dest_location.name)
    definition_data = {'wiki_slug': wiki_slug}

    modulestore('direct').create_and_save_xmodule(
        dest_location, definition_data=definition_data, 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, request.user)

    new_location = loc_mapper().translate_location(
        new_course.location.course_id, new_course.location, False, True)
    # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course
    # however, we can assume that b/c this user had authority to create the course, the user can add themselves
    CourseInstructorRole(new_location).add_users(request.user)
    auth.add_users(request.user, CourseStaffRole(new_location), request.user)

    # 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)
    _users_assign_default_role(new_course.location)

    return JsonResponse({'url': new_location.url_reverse("course/", "")})
Example #36
0
    def setUp(self):
        super(ContentGroupTestCase, self).setUp()

        self.course = CourseFactory.create(
            org='org',
            number='number',
            run='run',
            # This test needs to use a course that has already started --
            # discussion topics only show up if the course has already started,
            # and the default start date for courses is Jan 1, 2030.
            start=datetime(2012, 2, 3, tzinfo=UTC),
            user_partitions=[
                UserPartition(
                    0,
                    'Content Group Configuration',
                    '',
                    [Group(1, 'Alpha'), Group(2, 'Beta')],
                    scheme_id='cohort')
            ],
            grading_policy={
                "GRADER": [{
                    "type": "Homework",
                    "min_count": 1,
                    "drop_count": 0,
                    "short_label": "HW",
                    "weight": 1.0
                }]
            },
            cohort_config={'cohorted': True},
            discussion_topics={})

        seed_permissions_roles(self.course.id)

        self.staff_user = UserFactory.create(is_staff=True)
        self.alpha_user = UserFactory.create()
        self.beta_user = UserFactory.create()
        self.non_cohorted_user = UserFactory.create()
        self.community_ta = UserFactory.create(username="******")
        self.community_ta.roles.add(
            Role.objects.get(name="Community TA", course_id=self.course.id))
        for user in [
                self.staff_user, self.alpha_user, self.beta_user,
                self.non_cohorted_user, self.community_ta
        ]:
            CourseEnrollmentFactory.create(user=user, course_id=self.course.id)

        alpha_cohort = CohortFactory(
            course_id=self.course.id,
            name='Cohort Alpha',
            users=[self.alpha_user, self.community_ta, self.staff_user])
        beta_cohort = CohortFactory(course_id=self.course.id,
                                    name='Cohort Beta',
                                    users=[self.beta_user])
        CourseUserGroupPartitionGroup.objects.create(
            course_user_group=alpha_cohort,
            partition_id=self.course.user_partitions[0].id,
            group_id=self.course.user_partitions[0].groups[0].id)
        CourseUserGroupPartitionGroup.objects.create(
            course_user_group=beta_cohort,
            partition_id=self.course.user_partitions[0].id,
            group_id=self.course.user_partitions[0].groups[1].id)
        self.alpha_module = ItemFactory.create(
            parent_location=self.course.location,
            category='discussion',
            discussion_id='alpha_group_discussion',
            discussion_target='Visible to Alpha',
            group_access={
                self.course.user_partitions[0].id:
                [self.course.user_partitions[0].groups[0].id]
            })
        self.beta_module = ItemFactory.create(
            parent_location=self.course.location,
            category='discussion',
            discussion_id='beta_group_discussion',
            discussion_target='Visible to Beta',
            group_access={
                self.course.user_partitions[0].id:
                [self.course.user_partitions[0].groups[1].id]
            })
        self.global_module = ItemFactory.create(
            parent_location=self.course.location,
            category='discussion',
            discussion_id='global_group_discussion',
            discussion_target='Visible to Everyone')
        self.course = self.store.get_item(self.course.location)
Example #37
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not auth.has_access(request.user, CourseCreatorRole()):
        raise PermissionDenied()

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

    # allow/disable unicode characters in course_id according to settings
    if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'):
        if _has_non_ascii_characters(org) or _has_non_ascii_characters(number) or _has_non_ascii_characters(run):
            return JsonResponse(
                {'error': _('Special characters not allowed in organization, course number, and course run.')},
                status=400
            )

    try:
        course_key = SlashSeparatedCourseKey(org, number, run)

        # instantiate the CourseDescriptor and then persist it
        # note: no system to pass
        if display_name is None:
            metadata = {}
        else:
            metadata = {'display_name': display_name}

        # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for
        # existing xml courses this cannot be changed in CourseDescriptor.
        # # TODO get rid of defining wiki slug in this org/course/run specific way and reconcile
        # w/ xmodule.course_module.CourseDescriptor.__init__
        wiki_slug = u"{0}.{1}.{2}".format(course_key.org, course_key.course, course_key.run)
        definition_data = {'wiki_slug': wiki_slug}

        # Create the course then fetch it from the modulestore
        # Check if role permissions group for a course named like this already exists
        # Important because role groups are case insensitive
        if CourseRole.course_group_already_exists(course_key):
            raise InvalidLocationError()

        fields = {}
        fields.update(definition_data)
        fields.update(metadata)

        # Creating the course raises InvalidLocationError if an existing course with this org/name is found
        new_course = modulestore('direct').create_course(
            course_key.org,
            course_key.offering,
            fields=fields,
        )

        # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course
        # however, we can assume that b/c this user had authority to create the course, the user can add themselves
        CourseInstructorRole(new_course.id).add_users(request.user)
        auth.add_users(request.user, CourseStaffRole(new_course.id), request.user)

        # seed the forums
        seed_permissions_roles(new_course.id)

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

        return JsonResponse({
            'url': reverse_course_url('course_handler', new_course.id)
        })

    except InvalidLocationError:
        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.'),
        })
    except InvalidKeyError as error:
        return JsonResponse({
            "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=error.message)}
        )
Example #38
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            "staff": AdminFactory.create(password=self.test_password),
            "course_staff": StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password),
        }
        self.create_and_enroll_student(username="******")
        self.create_and_enroll_student(username="******")
        self.create_and_enroll_student(username="******", courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username="******")
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users["community_ta"])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2], username="******"
        )

        # Make this student have a public profile
        self.create_and_enroll_student(courses=[self.test_course_2], username="******")
        profile = self.users["student_enrolled_public_profile"].profile
        profile.year_of_birth = 1970
        profile.save()

        # This student is enrolled in the other course, but not yet a member of a team. This is to allow
        # course_2 to use a max_team_size of 1 without breaking other tests on course_1
        self.create_and_enroll_student(
            courses=[self.test_course_2], username="******"
        )

        with skip_signal(
            post_save,
            receiver=course_team_post_save_callback,
            sender=CourseTeam,
            dispatch_uid="teams.signals.course_team_post_save_callback",
        ):
            # 'solar team' is intentionally lower case to test case insensitivity in name ordering
            self.test_team_1 = CourseTeamFactory.create(
                name=u"sólar team", course_id=self.test_course_1.id, topic_id="topic_0"
            )
            self.test_team_2 = CourseTeamFactory.create(name="Wind Team", course_id=self.test_course_1.id)
            self.test_team_3 = CourseTeamFactory.create(name="Nuclear Team", course_id=self.test_course_1.id)
            self.test_team_4 = CourseTeamFactory.create(
                name="Coal Team", course_id=self.test_course_1.id, is_active=False
            )
            self.test_team_5 = CourseTeamFactory.create(name="Another Team", course_id=self.test_course_2.id)
            self.test_team_6 = CourseTeamFactory.create(
                name="Public Profile Team", course_id=self.test_course_2.id, topic_id="topic_6"
            )
            self.test_team_7 = CourseTeamFactory.create(
                name="Search",
                description="queryable text",
                country="GS",
                language="to",
                course_id=self.test_course_2.id,
                topic_id="topic_7",
            )

        self.test_team_name_id_map = {
            team.name: team
            for team in (
                self.test_team_1,
                self.test_team_2,
                self.test_team_3,
                self.test_team_4,
                self.test_team_5,
                self.test_team_6,
                self.test_team_7,
            )
        }

        for user, course in [("staff", self.test_course_1), ("course_staff", self.test_course_1)]:
            CourseEnrollment.enroll(self.users[user], course.id, check_access=True)

        self.test_team_1.add_user(self.users["student_enrolled"])
        self.test_team_3.add_user(self.users["student_enrolled_both_courses_other_team"])
        self.test_team_5.add_user(self.users["student_enrolled_both_courses_other_team"])
        self.test_team_6.add_user(self.users["student_enrolled_public_profile"])
Example #39
0
def create_ccx(request, course, ccx=None):
    """
    Create a new CCX
    """
    name = request.POST.get('name')

    if hasattr(course, 'ccx_connector') and course.ccx_connector:
        # if ccx connector url is set in course settings then inform user that he can
        # only create ccx by using ccx connector url.
        context = get_ccx_creation_dict(course)
        messages.error(request, context['use_ccx_con_error_message'])
        return render_to_response('ccx/coach_dashboard.html', context)

    # prevent CCX objects from being created for deprecated course ids.
    if course.id.deprecated:
        messages.error(
            request,
            _("You cannot create a CCX from a course using a deprecated id. "
              "Please create a rerun of this course in the studio to allow "
              "this action."))
        url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
        return redirect(url)

    ccx = CustomCourseForEdX(course_id=course.id,
                             coach=request.user,
                             display_name=name)
    ccx.save()

    # Make sure start/due are overridden for entire course
    start = TODAY().replace(tzinfo=pytz.UTC)
    override_field_for_ccx(ccx, course, 'start', start)
    override_field_for_ccx(ccx, course, 'due', None)

    # Enforce a static limit for the maximum amount of students that can be enrolled
    override_field_for_ccx(ccx, course, 'max_student_enrollments_allowed',
                           settings.CCX_MAX_STUDENTS_ALLOWED)

    # Hide anything that can show up in the schedule
    hidden = 'visible_to_staff_only'
    for chapter in course.get_children():
        override_field_for_ccx(ccx, chapter, hidden, True)
        for sequential in chapter.get_children():
            override_field_for_ccx(ccx, sequential, hidden, True)
            for vertical in sequential.get_children():
                override_field_for_ccx(ccx, vertical, hidden, True)

    ccx_id = CCXLocator.from_course_locator(course.id, unicode(ccx.id))

    # Create forum roles
    seed_permissions_roles(ccx_id)
    # Assign administrator forum role to CCX coach
    assign_role(ccx_id, request.user, FORUM_ROLE_ADMINISTRATOR)

    url = reverse('ccx_coach_dashboard', kwargs={'course_id': ccx_id})

    # Enroll the coach in the course
    email_params = get_email_params(course,
                                    auto_enroll=True,
                                    course_key=ccx_id,
                                    display_name=ccx.display_name)
    enroll_email(
        course_id=ccx_id,
        student_email=request.user.email,
        auto_enroll=True,
        email_students=True,
        email_params=email_params,
    )

    assign_staff_role_to_ccx(ccx_id, request.user, course.id)
    add_master_course_staff_to_ccx(course, ccx_id, ccx.display_name)

    # using CCX object as sender here.
    responses = SignalHandler.course_published.send(
        sender=ccx,
        course_key=CCXLocator.from_course_locator(course.id, unicode(ccx.id)))
    for rec, response in responses:
        log.info(
            'Signal fired when course is published. Receiver: %s. Response: %s',
            rec, response)

    return redirect(url)
Example #40
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.'),
        })

    # 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(dest_location.org, re.IGNORECASE),
        '_id.course': re.compile(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)

    return JsonResponse({'id': new_course.location.url()})
Example #41
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()})
    def handle(self, *args, **options):
        course_id = options['course_id']

        course_key = CourseKey.from_string(course_id)
        seed_permissions_roles(course_key)
Example #43
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            'staff': AdminFactory.create(password=self.test_password),
            'course_staff': StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password)
        }
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******', courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username='******')
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users['community_ta'])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2],
            username='******'
        )

        # Make this student have a public profile
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******'
        )
        profile = self.users['student_enrolled_public_profile'].profile
        profile.year_of_birth = 1970
        profile.save()

        # This student is enrolled in the other course, but not yet a member of a team. This is to allow
        # course_2 to use a max_team_size of 1 without breaking other tests on course_1
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******'
        )

        # 'solar team' is intentionally lower case to test case insensitivity in name ordering
        self.test_team_1 = CourseTeamFactory.create(
            name=u'sólar team',
            course_id=self.test_course_1.id,
            topic_id='topic_0'
        )
        self.test_team_2 = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id)
        self.test_team_3 = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id)
        self.test_team_4 = CourseTeamFactory.create(name='Coal Team', course_id=self.test_course_1.id, is_active=False)
        self.test_team_5 = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id)
        self.test_team_6 = CourseTeamFactory.create(
            name='Public Profile Team',
            course_id=self.test_course_2.id,
            topic_id='topic_6'
        )

        self.test_team_name_id_map = {team.name: team for team in (
            self.test_team_1,
            self.test_team_2,
            self.test_team_3,
            self.test_team_4,
            self.test_team_5,
        )}

        for user, course in [('staff', self.test_course_1), ('course_staff', self.test_course_1)]:
            CourseEnrollment.enroll(
                self.users[user], course.id, check_access=True
            )

        self.test_team_1.add_user(self.users['student_enrolled'])
        self.test_team_3.add_user(self.users['student_enrolled_both_courses_other_team'])
        self.test_team_5.add_user(self.users['student_enrolled_both_courses_other_team'])
        self.test_team_6.add_user(self.users['student_enrolled_public_profile'])
Example #44
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()})
Example #45
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            'staff':
            AdminFactory.create(password=self.test_password),
            'course_staff':
            StaffFactory.create(course_key=self.test_course_1.id,
                                password=self.test_password)
        }
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******',
                                       courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username='******')
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA,
                                             course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users['community_ta'])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2],
            username='******')

        # Make this student have a public profile
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******')
        profile = self.users['student_enrolled_public_profile'].profile
        profile.year_of_birth = 1970
        profile.save()

        # This student is enrolled in the other course, but not yet a member of a team. This is to allow
        # course_2 to use a max_team_size of 1 without breaking other tests on course_1
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******')

        # 'solar team' is intentionally lower case to test case insensitivity in name ordering
        self.test_team_1 = CourseTeamFactory.create(
            name=u'sólar team',
            course_id=self.test_course_1.id,
            topic_id='topic_0')
        self.test_team_2 = CourseTeamFactory.create(
            name='Wind Team', course_id=self.test_course_1.id)
        self.test_team_3 = CourseTeamFactory.create(
            name='Nuclear Team', course_id=self.test_course_1.id)
        self.test_team_4 = CourseTeamFactory.create(
            name='Coal Team', course_id=self.test_course_1.id, is_active=False)
        self.test_team_5 = CourseTeamFactory.create(
            name='Another Team', course_id=self.test_course_2.id)
        self.test_team_6 = CourseTeamFactory.create(
            name='Public Profile Team',
            course_id=self.test_course_2.id,
            topic_id='topic_6')

        self.test_team_name_id_map = {
            team.name: team
            for team in (
                self.test_team_1,
                self.test_team_2,
                self.test_team_3,
                self.test_team_4,
                self.test_team_5,
            )
        }

        for user, course in [('staff', self.test_course_1),
                             ('course_staff', self.test_course_1)]:
            CourseEnrollment.enroll(self.users[user],
                                    course.id,
                                    check_access=True)

        self.test_team_1.add_user(self.users['student_enrolled'])
        self.test_team_3.add_user(
            self.users['student_enrolled_both_courses_other_team'])
        self.test_team_5.add_user(
            self.users['student_enrolled_both_courses_other_team'])
        self.test_team_6.add_user(
            self.users['student_enrolled_public_profile'])
Example #46
0
 def setUp(self):
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
Example #47
0
def create_ccx(request, course, ccx=None):
    """
    Create a new CCX
    """
    name = request.POST.get('name')

    if hasattr(course, 'ccx_connector') and course.ccx_connector:
        # if ccx connector url is set in course settings then inform user that he can
        # only create ccx by using ccx connector url.
        context = get_ccx_creation_dict(course)
        messages.error(request, context['use_ccx_con_error_message'])
        return render_to_response('ccx/coach_dashboard.html', context)

    # prevent CCX objects from being created for deprecated course ids.
    if course.id.deprecated:
        messages.error(request, _(
            "You cannot create a CCX from a course using a deprecated id. "
            "Please create a rerun of this course in the studio to allow "
            "this action."))
        url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
        return redirect(url)

    ccx = CustomCourseForEdX(
        course_id=course.id,
        coach=request.user,
        display_name=name)
    ccx.save()

    # Make sure start/due are overridden for entire course
    start = TODAY().replace(tzinfo=pytz.UTC)
    override_field_for_ccx(ccx, course, 'start', start)
    override_field_for_ccx(ccx, course, 'due', None)

    # Enforce a static limit for the maximum amount of students that can be enrolled
    override_field_for_ccx(ccx, course, 'max_student_enrollments_allowed', settings.CCX_MAX_STUDENTS_ALLOWED)

    # Hide anything that can show up in the schedule
    hidden = 'visible_to_staff_only'
    for chapter in course.get_children():
        override_field_for_ccx(ccx, chapter, hidden, True)
        for sequential in chapter.get_children():
            override_field_for_ccx(ccx, sequential, hidden, True)
            for vertical in sequential.get_children():
                override_field_for_ccx(ccx, vertical, hidden, True)

    ccx_id = CCXLocator.from_course_locator(course.id, unicode(ccx.id))

    # Create forum roles
    seed_permissions_roles(ccx_id)
    # Assign administrator forum role to CCX coach
    assign_role(ccx_id, request.user, FORUM_ROLE_ADMINISTRATOR)

    url = reverse('ccx_coach_dashboard', kwargs={'course_id': ccx_id})

    # Enroll the coach in the course
    email_params = get_email_params(course, auto_enroll=True, course_key=ccx_id, display_name=ccx.display_name)
    enroll_email(
        course_id=ccx_id,
        student_email=request.user.email,
        auto_enroll=True,
        email_students=True,
        email_params=email_params,
    )

    assign_staff_role_to_ccx(ccx_id, request.user, course.id)
    add_master_course_staff_to_ccx(course, ccx_id, ccx.display_name)

    # using CCX object as sender here.
    responses = SignalHandler.course_published.send(
        sender=ccx,
        course_key=CCXLocator.from_course_locator(course.id, unicode(ccx.id))
    )
    for rec, response in responses:
        log.info('Signal fired when course is published. Receiver: %s. Response: %s', rec, response)

    return redirect(url)
Example #48
0
    def setUp(self):
        super(TeamAPITestCase, self).setUp()
        self.topics_count = 4
        self.users = {
            'staff': AdminFactory.create(password=self.test_password),
            'course_staff': StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password)
        }
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******')
        self.create_and_enroll_student(username='******', courses=[])

        # Make this student a community TA.
        self.create_and_enroll_student(username='******')
        seed_permissions_roles(self.test_course_1.id)
        community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=self.test_course_1.id)
        community_ta_role.users.add(self.users['community_ta'])

        # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
        # same team as student_enrolled.
        self.create_and_enroll_student(
            courses=[self.test_course_1, self.test_course_2],
            username='******'
        )

        # Make this student have a public profile
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******'
        )
        profile = self.users['student_enrolled_public_profile'].profile
        profile.year_of_birth = 1970
        profile.save()

        # This student is enrolled in the other course, but not yet a member of a team. This is to allow
        # course_2 to use a max_team_size of 1 without breaking other tests on course_1
        self.create_and_enroll_student(
            courses=[self.test_course_2],
            username='******'
        )

        with skip_signal(
            post_save,
            receiver=course_team_post_save_callback,
            sender=CourseTeam,
            dispatch_uid='teams.signals.course_team_post_save_callback'
        ):
            self.solar_team = CourseTeamFactory.create(
                name=u'Sólar team',
                course_id=self.test_course_1.id,
                topic_id='topic_0'
            )
            self.wind_team = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id)
            self.nuclear_team = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id)
            self.another_team = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id)
            self.public_profile_team = CourseTeamFactory.create(
                name='Public Profile Team',
                course_id=self.test_course_2.id,
                topic_id='topic_6'
            )
            self.search_team = CourseTeamFactory.create(
                name='Search',
                description='queryable text',
                country='GS',
                language='to',
                course_id=self.test_course_2.id,
                topic_id='topic_7'
            )

        self.test_team_name_id_map = {team.name: team for team in (
            self.solar_team,
            self.wind_team,
            self.nuclear_team,
            self.another_team,
            self.public_profile_team,
            self.search_team,
        )}

        for user, course in [('staff', self.test_course_1), ('course_staff', self.test_course_1)]:
            CourseEnrollment.enroll(
                self.users[user], course.id, check_access=True
            )

        self.solar_team.add_user(self.users['student_enrolled'])
        self.nuclear_team.add_user(self.users['student_enrolled_both_courses_other_team'])
        self.another_team.add_user(self.users['student_enrolled_both_courses_other_team'])
        self.public_profile_team.add_user(self.users['student_enrolled_public_profile'])
Example #49
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not auth.has_access(request.user, CourseCreatorRole()):
        raise PermissionDenied()

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

    # allow/disable unicode characters in course_id according to settings
    if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'):
        if _has_non_ascii_characters(org) or _has_non_ascii_characters(
                number) or _has_non_ascii_characters(run):
            return JsonResponse(
                {
                    'error':
                    _('Special characters not allowed in organization, course number, and course run.'
                      )
                },
                status=400)

    try:
        course_key = SlashSeparatedCourseKey(org, number, run)

        # instantiate the CourseDescriptor and then persist it
        # note: no system to pass
        if display_name is None:
            metadata = {}
        else:
            metadata = {'display_name': display_name}

        # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for
        # existing xml courses this cannot be changed in CourseDescriptor.
        # # TODO get rid of defining wiki slug in this org/course/run specific way and reconcile
        # w/ xmodule.course_module.CourseDescriptor.__init__
        wiki_slug = u"{0}.{1}.{2}".format(course_key.org, course_key.course,
                                          course_key.run)
        definition_data = {'wiki_slug': wiki_slug}

        # Create the course then fetch it from the modulestore
        # Check if role permissions group for a course named like this already exists
        # Important because role groups are case insensitive
        if CourseRole.course_group_already_exists(course_key):
            raise InvalidLocationError()

        fields = {}
        fields.update(definition_data)
        fields.update(metadata)

        # Creating the course raises InvalidLocationError if an existing course with this org/name is found
        new_course = modulestore('direct').create_course(
            course_key.org,
            course_key.offering,
            fields=fields,
        )

        # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course
        # however, we can assume that b/c this user had authority to create the course, the user can add themselves
        CourseInstructorRole(new_course.id).add_users(request.user)
        auth.add_users(request.user, CourseStaffRole(new_course.id),
                       request.user)

        # seed the forums
        seed_permissions_roles(new_course.id)

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

        return JsonResponse(
            {'url': reverse_course_url('course_handler', new_course.id)})

    except InvalidLocationError:
        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.'),
        })
    except InvalidKeyError as error:
        return JsonResponse({
            "ErrMsg":
            _("Unable to create course '{name}'.\n\n{err}").format(
                name=display_name, err=error.message)
        })
Example #50
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/", "")})
Example #51
0
 def setUp(self):
     self.course = CourseFactory.create()
     seed_permissions_roles(self.course.id)
     self.student = UserFactory.create()
     CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
    def handle(self, *args, **options):
        course_id = options['course_id']

        course_key = CourseKey.from_string(course_id)
        seed_permissions_roles(course_key)
Example #53
0
def create_new_course(request):
    """
    Create a new course.

    Returns the URL for the course overview page.
    """
    if not auth.has_access(request.user, CourseCreatorRole()):
        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(u'i4x', org, number, u'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
        # pylint: disable=E1101
        '_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE),
        # pylint: disable=E1101
        '_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE),
        '_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, request.user)

    new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True)
    # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course
    # however, we can assume that b/c this user had authority to create the course, the user can add themselves
    CourseInstructorRole(new_location).add_users(request.user)
    auth.add_users(request.user, CourseStaffRole(new_location), request.user)

    # 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/", "")})
Example #54
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/", "")})