def setUp(self): """ Set up tests """ super().setUp() # add some info about the course for easy access self.master_course_key = self.course.location.course_key self.master_course_key_str = str(self.master_course_key) # OAUTH2 setup # create a specific user for the application self.app_user = app_user = UserFactory( username='******', email='*****@*****.**', password=USER_PASSWORD ) # add staff role to the app user CourseStaffRole(self.master_course_key).add_users(app_user) # adding instructor to master course. instructor = UserFactory() allow_access(self.course, instructor, 'instructor') self.auth = self.prepare_auth_token(app_user) self.course.enable_ccx = True self.mstore.update_item(self.course, self.coach.id) # making the master course chapters easily available self.master_course_chapters = courses.get_course_chapter_ids(self.master_course_key)
def change_existing_ccx_coaches_to_staff(apps, schema_editor): """ Modify all coaches of CCX courses so that they have the staff role on the CCX course they coach, but retain the CCX Coach role on the parent course. Arguments: apps (Applications): Apps in edX platform. schema_editor (SchemaEditor): For editing database schema (unused) """ CustomCourseForEdX = apps.get_model('ccx', 'CustomCourseForEdX') db_alias = schema_editor.connection.alias if not db_alias == 'default': # This migration is not intended to run against the student_module_history database and # will fail if it does. Ensure that it'll only run against the default database. return list_ccx = CustomCourseForEdX.objects.using(db_alias).all() for ccx in list_ccx: ccx_locator = CCXLocator.from_course_locator(ccx.course_id, six.text_type(ccx.id)) try: course = get_course_by_id(ccx_locator) except Http404: log.error('Could not migrate access for CCX course: %s', six.text_type(ccx_locator)) else: coach = User.objects.get(id=ccx.coach.id) allow_access(course, coach, 'staff', send_email=False) revoke_access(course, coach, 'ccx_coach', send_email=False) log.info( 'The CCX coach of CCX %s has been switched from "CCX Coach" to "Staff".', six.text_type(ccx_locator))
def create_users(course_key, user_data, enrollment_mode=None, course_staff=False, activate=False): """Create users, enrolling them in course_key if it's not None""" for single_user_data in user_data: account_creation_form = AccountCreationForm(data=single_user_data, tos_required=False) (user, _, _) = do_create_account(account_creation_form) if activate: user.is_active = True user.save() if course_key is not None: CourseEnrollment.enroll(user, course_key, mode=enrollment_mode) if course_staff: course = modulestore().get_course(course_key, depth=1) allow_access(course, user, 'staff', send_email=False) if course_key and course_staff: print(f'Created user {user.username} as course staff') else: print(f'Created user {user.username}')
def revert_ccx_staff_to_coaches(apps, schema_editor): """ Modify all staff on CCX courses so that they no longer have the staff role on the course that they coach. Arguments: apps (Applications): Apps in edX platform. schema_editor (SchemaEditor): For editing database schema (unused) """ CustomCourseForEdX = apps.get_model('ccx', 'CustomCourseForEdX') db_alias = schema_editor.connection.alias if not db_alias == 'default': return list_ccx = CustomCourseForEdX.objects.using(db_alias).all() for ccx in list_ccx: ccx_locator = CCXLocator.from_course_locator(ccx.course_id, six.text_type(ccx.id)) try: course = get_course_by_id(ccx_locator) except Http404: log.error('Could not migrate access for CCX course: %s', six.text_type(ccx_locator)) else: coach = User.objects.get(id=ccx.coach.id) allow_access(course, coach, 'ccx_coach', send_email=False) revoke_access(course, coach, 'staff', send_email=False) log.info( 'The CCX coach of CCX %s has been switched from "Staff" to "CCX Coach".', six.text_type(ccx_locator))
def setUp(self): super(TestInstructorAccessRevoke, self).setUp() self.staff = [UserFactory.create() for _ in xrange(4)] for user in self.staff: allow_access(self.course, user, 'staff') self.beta_testers = [UserFactory.create() for _ in xrange(4)] for user in self.beta_testers: allow_access(self.course, user, 'beta')
def setUp(self): super(TestInstructorAccessRevoke, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.staff = [UserFactory.create() for _ in range(4)] for user in self.staff: allow_access(self.course, user, 'staff') self.beta_testers = [UserFactory.create() for _ in range(4)] for user in self.beta_testers: allow_access(self.course, user, 'beta')
def setUp(self): super(TestInstructorAccessList, self).setUp() self.instructors = [UserFactory.create() for _ in xrange(4)] for user in self.instructors: allow_access(self.course, user, 'instructor') self.beta_testers = [UserFactory.create() for _ in xrange(4)] for user in self.beta_testers: allow_access(self.course, user, 'beta')
def setUp(self): super().setUp() self.course = course = CourseFactory.create(enable_ccx=True) # Create a course outline self.mooc_start = start = datetime.datetime( 2010, 5, 12, 2, 42, tzinfo=UTC ) self.mooc_due = due = datetime.datetime( 2010, 7, 7, 0, 0, tzinfo=UTC ) self.chapters = [ ItemFactory.create(start=start, parent=course) for _ in range(2) ] self.sequentials = flatten([ [ ItemFactory.create(parent=chapter) for _ in range(2) ] for chapter in self.chapters ]) self.verticals = flatten([ [ ItemFactory.create( start=start, due=due, parent=sequential, graded=True, format='Homework', category='vertical' ) for _ in range(2) ] for sequential in self.sequentials ]) # Trying to wrap the whole thing in a bulk operation fails because it # doesn't find the parents. But we can at least wrap this part... with self.store.bulk_operations(course.id, emit_signals=False): blocks = flatten([ # pylint: disable=unused-variable [ ItemFactory.create(parent=vertical) for _ in range(2) ] for vertical in self.verticals ]) # Create instructor account self.coach = UserFactory.create() # create an instance of modulestore self.mstore = modulestore() # Login with the instructor account self.client.login(username=self.coach.username, password="******") # adding staff to master course. staff = UserFactory() allow_access(self.course, staff, 'staff') assert CourseStaffRole(self.course.id).has_user(staff) # adding instructor to master course. instructor = UserFactory() allow_access(self.course, instructor, 'instructor') assert CourseInstructorRole(self.course.id).has_user(instructor) assert modulestore().has_course(self.course.id)
def test_is_user_staff(self): """ Test to assert that the user is staff or not """ result = self.service.is_course_staff(self.student, unicode(self.course.id)) self.assertFalse(result) # allow staff access to the student allow_access(self.course, self.student, "staff") result = self.service.is_course_staff(self.student, unicode(self.course.id)) self.assertTrue(result)
def test_ccx_tab_visibility_for_staff_ccx_course(self): """ Staff can access coach dashboard on ccx course. """ self.make_coach() ccx = self.make_ccx() ccx_key = CCXLocator.from_course_locator(self.course.id, str(ccx.id)) staff = self.make_staff() with ccx_course(ccx_key) as course_ccx: allow_access(course_ccx, staff, 'staff') assert self.check_ccx_tab(course_ccx, staff)
def test_ccx_tab_visibility_for_instructor_ccx_course(self): """ Instructor can access coach dashboard on ccx course. """ self.make_coach() ccx = self.make_ccx() ccx_key = CCXLocator.from_course_locator(self.course.id, str(ccx.id)) instructor = self.make_instructor() with ccx_course(ccx_key) as course_ccx: allow_access(course_ccx, instructor, 'instructor') assert self.check_ccx_tab(course_ccx, instructor)
def test_is_user_staff(self): """ Test to assert that the user is staff or not """ result = self.service.is_course_staff(self.student, str(self.course.id)) assert not result # allow staff access to the student allow_access(self.course, self.student, 'staff') result = self.service.is_course_staff(self.student, str(self.course.id)) assert result
def test_is_user_staff(self): """ Test to assert that the user is staff or not """ result = self.service.is_course_staff(self.student, six.text_type(self.course.id)) self.assertFalse(result) # allow staff access to the student allow_access(self.course, self.student, 'staff') result = self.service.is_course_staff(self.student, six.text_type(self.course.id)) self.assertTrue(result)
def create_users( course_key, user_data, enrollment_mode=None, course_staff=False, activate=False, ignore_user_already_exists=False, ): """Create users, enrolling them in course_key if it's not None""" for single_user_data in user_data: account_creation_form = AccountCreationForm( data=single_user_data, tos_required=False ) user_already_exists = False try: (user, _, _) = do_create_account(account_creation_form) except (ValidationError, AccountValidationError) as account_creation_error: # It would be convenient if we just had the AccountValidationError raised, because we include a # helpful error code in there, but we also do form validation on account_creation_form and those # are pretty opaque. try: # Check to see if there's a user with our username. If the username and email match our input, # we're good, it's the same user, probably. If the email doesn't match, just to be safe we will # continue to fail. user = User.objects.get(username=single_user_data['username']) if user.email == single_user_data['email'] and ignore_user_already_exists: user_already_exists = True print(f'Test user {user.username} already exists. Continuing to attempt to enroll.') else: raise account_creation_error except User.DoesNotExist: # If a user with the username doesn't exist the error was probably something else, so reraise raise account_creation_error # pylint: disable=raise-missing-from if activate: user.is_active = True user.save() if course_key is not None: CourseEnrollment.enroll(user, course_key, mode=enrollment_mode) if course_staff: course = modulestore().get_course(course_key, depth=1) allow_access(course, user, 'staff', send_email=False) if course_key and course_staff and not user_already_exists: print(f'Created user {user.username} as course staff') elif not user_already_exists: print(f'Created user {user.username}')
def setUp(self): """ Set up tests """ super().setUp() # Login with the instructor account self.client.login(username=self.coach.username, password="******") # adding staff to master course. staff = UserFactory() allow_access(self.course, staff, 'staff') assert CourseStaffRole(self.course.id).has_user(staff) # adding instructor to master course. instructor = UserFactory() allow_access(self.course, instructor, 'instructor') assert CourseInstructorRole(self.course.id).has_user(instructor)
def assign_staff_role_to_ccx(ccx_locator, user, master_course_id): """ Check if user has ccx_coach role on master course then assign them staff role on ccx only if role is not already assigned. Because of this coach can open dashboard from master course as well as ccx. :param ccx_locator: CCX key :param user: User to whom we want to assign role. :param master_course_id: Master course key """ coach_role_on_master_course = CourseCcxCoachRole(master_course_id) # check if user has coach role on master course if coach_role_on_master_course.has_user(user): # Check if user has staff role on ccx. role = CourseStaffRole(ccx_locator) if not role.has_user(user): # assign user the staff role on ccx with ccx_course(ccx_locator) as course: allow_access(course, user, "staff", send_email=False)
def assign_staff_role_to_ccx(ccx_locator, user, master_course_id): """ Check if user has ccx_coach role on master course then assign him staff role on ccx only if role is not already assigned. Because of this coach can open dashboard from master course as well as ccx. :param ccx_locator: CCX key :param user: User to whom we want to assign role. :param master_course_id: Master course key """ coach_role_on_master_course = CourseCcxCoachRole(master_course_id) # check if user has coach role on master course if coach_role_on_master_course.has_user(user): # Check if user has staff role on ccx. role = CourseStaffRole(ccx_locator) if not role.has_user(user): # assign user the staff role on ccx with ccx_course(ccx_locator) as course: allow_access(course, user, "staff", send_email=False)
def setUp(self): super(TestStaffOnCCX, self).setUp() # Create instructor account self.client.login(username=self.coach.username, password="******") # create an instance of modulestore self.mstore = modulestore() # adding staff to master course. staff = UserFactory() allow_access(self.course, staff, 'staff') self.assertTrue(CourseStaffRole(self.course.id).has_user(staff)) # adding instructor to master course. instructor = UserFactory() allow_access(self.course, instructor, 'instructor') self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
def setUp(self): super(TestStaffOnCCX, self).setUp() # Create instructor account self.client.login(username=self.coach.username, password="******") # create an instance of modulestore self.mstore = modulestore() # adding staff to master course. staff = UserFactory() allow_access(self.course, staff, 'staff') self.assertTrue(CourseStaffRole(self.course.id).has_user(staff)) # adding instructor to master course. instructor = UserFactory() allow_access(self.course, instructor, 'instructor') self.assertTrue( CourseInstructorRole(self.course.id).has_user(instructor))
def test_allow_noneuser(self): user = None with pytest.raises(Exception): allow_access(self.course, user, 'staff')
def test_allow_badlevel(self): user = UserFactory() with pytest.raises(ValueError): allow_access(self.course, user, 'robot-not-a-level')
def test_allow_beta(self): """ Test allow beta against list beta. """ user = UserFactory() allow_access(self.course, user, 'beta') self.assertTrue(CourseBetaTesterRole(self.course.id).has_user(user))
def test_allow_badlevel(self): user = UserFactory() allow_access(self.course, user, 'robot-not-a-level')
def test_allow_noneuser(self): user = None allow_access(self.course, user, 'staff')
def add_master_course_staff_to_ccx(master_course, ccx_key, display_name, send_email=True): """ Add staff and instructor roles on ccx to all the staff and instructors members of master course. Arguments: master_course (CourseDescriptorWithMixins): Master course instance. ccx_key (CCXLocator): CCX course key. display_name (str): ccx display name for email. send_email (bool): flag to switch on or off email to the users on access grant. """ list_staff = list_with_level(master_course, 'staff') list_instructor = list_with_level(master_course, 'instructor') with ccx_course(ccx_key) as course_ccx: email_params = get_email_params(course_ccx, auto_enroll=True, course_key=ccx_key, display_name=display_name) list_staff_ccx = list_with_level(course_ccx, 'staff') list_instructor_ccx = list_with_level(course_ccx, 'instructor') for staff in list_staff: # this call should be idempotent if staff not in list_staff_ccx: try: # Enroll the staff in the ccx enroll_email( course_id=ccx_key, student_email=staff.email, auto_enroll=True, email_students=send_email, email_params=email_params, ) # allow 'staff' access on ccx to staff of master course allow_access(course_ccx, staff, 'staff') except CourseEnrollmentException: log.warning( "Unable to enroll staff %s to course with id %s", staff.email, ccx_key ) continue except SMTPException: continue for instructor in list_instructor: # this call should be idempotent if instructor not in list_instructor_ccx: try: # Enroll the instructor in the ccx enroll_email( course_id=ccx_key, student_email=instructor.email, auto_enroll=True, email_students=send_email, email_params=email_params, ) # allow 'instructor' access on ccx to instructor of master course allow_access(course_ccx, instructor, 'instructor') except CourseEnrollmentException: log.warning( "Unable to enroll instructor %s to course with id %s", instructor.email, ccx_key ) continue except SMTPException: continue
def test_allow_twice(self): user = UserFactory() allow_access(self.course, user, 'staff') allow_access(self.course, user, 'staff') self.assertTrue(CourseStaffRole(self.course.id).has_user(user))
def add_master_course_staff_to_ccx(master_course, ccx_key, display_name, send_email=True): """ Add staff and instructor roles on ccx to all the staff and instructors members of master course. Arguments: master_course (CourseBlockWithMixins): Master course instance. ccx_key (CCXLocator): CCX course key. display_name (str): ccx display name for email. send_email (bool): flag to switch on or off email to the users on access grant. """ list_staff = list_with_level(master_course.id, 'staff') list_instructor = list_with_level(master_course.id, 'instructor') with ccx_course(ccx_key) as course_ccx: email_params = get_email_params(course_ccx, auto_enroll=True, course_key=ccx_key, display_name=display_name) list_staff_ccx = list_with_level(course_ccx.id, 'staff') list_instructor_ccx = list_with_level(course_ccx.id, 'instructor') for staff in list_staff: # this call should be idempotent if staff not in list_staff_ccx: try: # Enroll the staff in the ccx enroll_email( course_id=ccx_key, student_email=staff.email, auto_enroll=True, email_students=send_email, email_params=email_params, ) # allow 'staff' access on ccx to staff of master course allow_access(course_ccx, staff, 'staff') except CourseEnrollmentException: log.warning( "Unable to enroll staff %s to course with id %s", staff.email, ccx_key) continue except SMTPException: continue for instructor in list_instructor: # this call should be idempotent if instructor not in list_instructor_ccx: try: # Enroll the instructor in the ccx enroll_email( course_id=ccx_key, student_email=instructor.email, auto_enroll=True, email_students=send_email, email_params=email_params, ) # allow 'instructor' access on ccx to instructor of master course allow_access(course_ccx, instructor, 'instructor') except CourseEnrollmentException: log.warning( "Unable to enroll instructor %s to course with id %s", instructor.email, ccx_key) continue except SMTPException: continue
def test_allow_ccx_coach(self): user = UserFactory() allow_access(self.course, user, 'ccx_coach') self.assertTrue(CourseCcxCoachRole(self.course.id).has_user(user))