def setUp(self): super().setUp() self.user = UserFactory.create() for course in [self.ccx_enabled_course, self.ccx_disabled_course]: CourseEnrollmentFactory.create(user=self.user, course_id=course.id) role = CourseCcxCoachRole(course.id) role.add_users(self.user)
def setUp(self): """ Set up courses and enrollments. """ super().setUp() # Create a Draft Mongo and a Split Mongo course and enroll a student user in them. self.student_password = "******" self.student = UserFactory.create(username="******", password=self.student_password, is_staff=False) self.draft_course = SampleCourseFactory.create(default_store=ModuleStoreEnum.Type.mongo) self.split_course = SampleCourseFactory.create(default_store=ModuleStoreEnum.Type.split) CourseEnrollment.enroll(self.student, self.draft_course.id) CourseEnrollment.enroll(self.student, self.split_course.id) # Create a CCX coach. self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.split_course.id) role.add_users(self.coach) # Create a CCX course and enroll the user in it. self.ccx = CcxFactory(course_id=self.split_course.id, coach=self.coach) last_week = datetime.datetime.now(UTC) - datetime.timedelta(days=7) override_field_for_ccx(self.ccx, self.split_course, 'start', last_week) # Required by self.ccx.has_started(). self.ccx_course_key = CCXLocator.from_course_locator(self.split_course.id, self.ccx.id) CourseEnrollment.enroll(self.student, self.ccx_course_key)
def setUp(self): """Set up a course, coach, ccx and user""" super().setUp() self.course = CourseFactory.create() coach = self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(coach)
def test_post_list(self): """ Test the creation of a CCX """ outbox = self.get_outbox() data = { 'master_course_id': self.master_course_key_str, 'max_students_allowed': 111, 'display_name': 'CCX Test Title', 'coach_email': self.coach.email, 'course_modules': self.master_course_chapters[0:1] } resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth) assert resp.status_code == status.HTTP_201_CREATED # check if the response has at least the same data of the request for key, val in data.items(): assert resp.data.get(key) == val assert 'ccx_course_id' in resp.data # check that the new CCX actually exists course_key = CourseKey.from_string(resp.data.get('ccx_course_id')) ccx_course = CustomCourseForEdX.objects.get(pk=course_key.ccx) assert str(CCXLocator.from_course_locator(ccx_course.course.id, ccx_course.id)) ==\ resp.data.get('ccx_course_id') # check that the coach user has coach role on the master course coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key) assert coach_role_on_master_course.has_user(self.coach) # check that the coach has been enrolled in the ccx ccx_course_object = get_course_by_id(course_key) assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=self.coach).exists() # check that an email has been sent to the coach assert len(outbox) == 1 assert self.coach.email in outbox[0].recipients()
def has_ccx_coach_role(user, course_key): """ Check if user is a coach on this ccx. Arguments: user (User): the user whose descriptor access we are checking. course_key (CCXLocator): Key to CCX. Returns: bool: whether user is a coach on this ccx or not. """ if hasattr(course_key, 'ccx'): ccx_id = course_key.ccx role = CourseCcxCoachRole(course_key) if role.has_user(user): list_ccx = CustomCourseForEdX.objects.filter( course_id=course_key.to_course_locator(), coach=user) if list_ccx.exists(): coach_ccx = list_ccx[0] return str(coach_ccx.id) == ccx_id else: raise CCXLocatorValidationException( "Invalid CCX key. To verify that " "user is a coach on CCX, you must provide key to CCX") return False
def setUp(self): super().setUp() coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(coach) self.ccx = CcxFactory(course_id=self.course.id, coach=coach) self.course_key = CCXLocator.from_course_locator(self.course.id, self.ccx.id)
def test_patch_detail(self): """ Test for successful patch """ outbox = self.get_outbox() # create a new coach new_coach = AdminFactory.create() data = { 'max_students_allowed': 111, 'display_name': 'CCX Title', 'coach_email': new_coach.email } resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth) assert resp.status_code == status.HTTP_204_NO_CONTENT ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id) assert ccx_from_db.max_student_enrollments_allowed == data['max_students_allowed'] assert ccx_from_db.display_name == data['display_name'] assert ccx_from_db.coach.email == data['coach_email'] # check that the coach user has coach role on the master course coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key) assert coach_role_on_master_course.has_user(new_coach) # check that the coach has been enrolled in the ccx ccx_course_object = get_course_by_id(self.ccx_key) assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=new_coach).exists() # check that an email has been sent to the coach assert len(outbox) == 1 assert new_coach.email in outbox[0].recipients()
def setUp(self): """Set up a course, coach, ccx and user""" super(TestGetCCXFromCCXLocator, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.course = CourseFactory.create() coach = self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(coach)
def test_ccx_tab_visibility_for_instructor_when_coach_master_course(self): """ Instructor can view ccx coach dashboard only if he is coach on master course. """ instructor = self.make_instructor() role = CourseCcxCoachRole(self.course.id) role.add_users(instructor) assert self.check_ccx_tab(self.course, instructor)
def setUp(self): """common setup for all tests""" super(TestCCX, self).setUp() self.course = CourseFactory.create() self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach) self.ccx = CcxFactory(course_id=self.course.id, coach=self.coach)
def test_ccx_tab_visibility_for_staff_when_coach_master_course(self): """ Staff can view ccx coach dashboard only if he is coach on master course. """ staff = self.make_staff() role = CourseCcxCoachRole(self.course.id) role.add_users(staff) assert self.check_ccx_tab(self.course, staff)
def setUp(self): super(TestRenderMessageToString, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(coach) self.ccx = CcxFactory(course_id=self.course.id, coach=coach) self.course_key = CCXLocator.from_course_locator( self.course.id, self.ccx.id)
def setUp(self): """common setup for all tests""" super(TestCCX, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.course = CourseFactory.create() self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach) self.ccx = CcxFactory(course_id=self.course.id, coach=self.coach)
def make_user_coach(user, master_course_key): """ Makes an user coach on the master course. This function is needed because an user cannot become a coach of the CCX if s/he is not coach on the master course. Args: user (User): User object master_course_key (CourseKey): Key locator object for the course """ coach_role_on_master_course = CourseCcxCoachRole(master_course_key) coach_role_on_master_course.add_users(user)
def setUp(self): """ Set up tests """ super(CoachAccessTestCaseCCX, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments # Create ccx coach account self.coach = AdminFactory.create(password="******") self.client.login(username=self.coach.username, password="******") # assign role to coach role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach) self.request_factory = RequestFactory()
def is_enabled(cls, course, user=None): """ Returns true if CCX has been enabled and the specified user is a coach """ if not settings.FEATURES.get('CUSTOM_COURSES_EDX', False) or not course.enable_ccx: # If ccx is not enable do not show ccx coach tab. return False if hasattr(course.id, 'ccx') and bool(user.has_perm(VIEW_CCX_COACH_DASHBOARD, course)): return True # check if user has coach access. role = CourseCcxCoachRole(course.id) return role.has_user(user)
def setUp(self): """ Set up tests """ super().setUp() # Create ccx coach account self.coach = AdminFactory.create(password="******") self.client.login(username=self.coach.username, password="******") # assign role to coach role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach) self.request_factory = RequestFactory()
def setUp(self): """ Set up tests """ super(TestSendCCXCoursePublished, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments course = self.course = CourseFactory.create(org="edX", course="999", display_name="Run 666") course2 = self.course2 = CourseFactory.create(org="edX", course="999a", display_name="Run 667") coach = AdminFactory.create() role = CourseCcxCoachRole(course.id) role.add_users(coach) self.ccx = CcxFactory(course_id=course.id, coach=coach) self.ccx2 = CcxFactory(course_id=course.id, coach=coach) self.ccx3 = CcxFactory(course_id=course.id, coach=coach) self.ccx4 = CcxFactory(course_id=course2.id, coach=coach)
def setUp(self): super(TestGetEmailParamsCCX, self).setUp() self.coach = AdminFactory.create() role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach) self.ccx = CcxFactory(course_id=self.course.id, coach=self.coach) self.course_key = CCXLocator.from_course_locator( self.course.id, self.ccx.id) # Explicitly construct what we expect the course URLs to be site = settings.SITE_NAME self.course_url = u'https://{}/courses/{}/'.format( site, self.course_key) self.course_about_url = self.course_url + 'about' self.registration_url = u'https://{}/register'.format(site)
def make_ccx(self): """ create ccx """ ccx = CustomCourseForEdX(course_id=self.course.id, coach=self.coach, display_name="Test CCX") ccx.save() ccx_locator = CCXLocator.from_course_locator(self.course.id, str(ccx.id)) role = CourseCcxCoachRole(ccx_locator) role.add_users(self.coach) CourseEnrollment.enroll(self.coach, ccx_locator) return ccx_locator
def setUp(self): """ Set up tests """ super().setUp() # Create instructor account self.coach = coach = AdminFactory.create() self.client.login(username=coach.username, password="******") # Create CCX role = CourseCcxCoachRole(self._course.id) role.add_users(coach) ccx = CcxFactory(course_id=self._course.id, coach=self.coach) # override course grading policy and make last section invisible to students override_field_for_ccx(ccx, self._course, 'grading_policy', { 'GRADER': [ {'drop_count': 0, 'min_count': 2, 'short_label': 'HW', 'type': 'Homework', 'weight': 1} ], 'GRADE_CUTOFFS': {'Pass': 0.75}, }) override_field_for_ccx( ccx, self.sections[-1], 'visible_to_staff_only', True ) # create a ccx locator and retrieve the course structure using that key # which emulates how a student would get access. self.ccx_key = CCXLocator.from_course_locator(self._course.id, str(ccx.id)) self.course = get_course_by_id(self.ccx_key, depth=None) CourseOverview.load_from_module_store(self.course.id) setup_students_and_grades(self) self.client.login(username=coach.username, password="******") self.addCleanup(RequestCache.clear_all_namespaces) from xmodule.modulestore.django import SignalHandler # using CCX object as sender here. SignalHandler.course_published.send( sender=ccx, course_key=self.ccx_key )
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 test_create_ccx_with_ccx_connector_set(self): """ Assert that coach cannot create ccx when ``ccx_connector`` url is set. """ role = CourseCcxCoachRole(self.course_with_ccx_connect_set.id) role.add_users(self.coach) url = reverse( 'create_ccx', kwargs={'course_id': str(self.course_with_ccx_connect_set.id)}) response = self.client.get(url) assert response.status_code == 200 error_message = _( "A CCX can only be created on this course through an external service." " Contact a course admin to give you access." ) assert re.search(error_message, response.content.decode('utf-8'))
def setUp(self): """ Set up tests """ super().setUp() course = self.course = CourseFactory.create(org="edX", course="999", display_name="Run 666") course2 = self.course2 = CourseFactory.create(org="edX", course="999a", display_name="Run 667") coach = AdminFactory.create() role = CourseCcxCoachRole(course.id) role.add_users(coach) self.ccx = CcxFactory(course_id=course.id, coach=coach) self.ccx2 = CcxFactory(course_id=course.id, coach=coach) self.ccx3 = CcxFactory(course_id=course.id, coach=coach) self.ccx4 = CcxFactory(course_id=course2.id, coach=coach)
def wrapper(request, course_id): """ Wraps the view function, performing access check, loading the course, and modifying the view's call signature. """ course_key = CourseKey.from_string(course_id) ccx = None if isinstance(course_key, CCXLocator): ccx_id = course_key.ccx try: ccx = CustomCourseForEdX.objects.get(pk=ccx_id) except CustomCourseForEdX.DoesNotExist: raise Http404 # lint-amnesty, pylint: disable=raise-missing-from if ccx: course_key = ccx.course_id course = get_course_by_id(course_key, depth=None) if not course.enable_ccx: # lint-amnesty, pylint: disable=no-else-raise raise Http404 else: if bool(request.user.has_perm(VIEW_CCX_COACH_DASHBOARD, course)): # if user is staff or instructor then he can view ccx coach dashboard. return view(request, course, ccx) else: # if there is a ccx, we must validate that it is the ccx for this coach role = CourseCcxCoachRole(course_key) if not role.has_user(request.user): return HttpResponseForbidden( _('You must be a CCX Coach to access this view.')) elif ccx is not None: coach_ccx = get_ccx_by_ccx_id(course, request.user, ccx.id) if coach_ccx is None: return HttpResponseForbidden( _('You must be the coach for this ccx to access this view' )) return view(request, course, ccx)
def test_authorization_no_oauth_other_coach(self): """ Check authorization for other coach users logged in without oauth """ # create an coach user coach_user = UserFactory.create( username='******', email='*****@*****.**', password='******', ) # add coach role to the coach user CourseCcxCoachRole(self.master_course_key).add_users(coach_user) data = {'display_name': 'CCX Title'} # the coach user cannot perform the request: this type of user can only get her own CCX self.client.login(username=coach_user.username, password=USER_PASSWORD) resp = self.client.get(self.detail_url) assert resp.status_code == status.HTTP_403_FORBIDDEN resp = self.client.patch(self.detail_url, data, format='json') assert resp.status_code == status.HTTP_403_FORBIDDEN
def test_authorization_no_oauth(self): """ Check authorization for coach users logged in without oauth """ # create an coach user coach_user = UserFactory( username='******', email='*****@*****.**', password=USER_PASSWORD ) # add coach role to the coach user CourseCcxCoachRole(self.master_course_key).add_users(coach_user) data = { 'master_course_id': self.master_course_key_str, 'max_students_allowed': 111, 'display_name': 'CCX Test Title', 'coach_email': self.coach.email } # the coach user cannot perform the request: this type of user can only get her own CCX self.client.login(username=coach_user.username, password=USER_PASSWORD) resp = self.client.get(self.list_url_master_course) assert resp.status_code == status.HTTP_403_FORBIDDEN resp = self.client.post(self.list_url, data, format='json') assert resp.status_code == status.HTTP_403_FORBIDDEN
def make_coach(self): """ create coach user """ role = CourseCcxCoachRole(self.course.id) role.add_users(self.coach)
def test_allow_ccx_coach(self): user = UserFactory() allow_access(self.course, user, 'ccx_coach') assert CourseCcxCoachRole(self.course.id).has_user(user)