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)
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)
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)
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)
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)
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)
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)
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]]))
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)
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], ] ), )
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)
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]]))
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)
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)
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()}))
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)
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')
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()})
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))
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'])
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)
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])
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'])
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)
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] )
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)
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)
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/", "")})
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)
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)} )
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"])
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)
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()})
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)
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'])
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'])
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 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)
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'])
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) })
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/", "")})
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/", "")})
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/", "")})