def test_locked_versioned_old_styleasset(self): """ Test that locked assets that are versioned (old-style) are being served. """ CourseEnrollment.enroll(self.non_staff_usr, self.course_key) self.assertTrue( CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key)) self.client.login(username=self.non_staff_usr, password='******') resp = self.client.get(self.url_locked_versioned_old_style) self.assertEqual(resp.status_code, 200)
def test_cannot_enroll_if_already_enrolled(self): """ Tests that a student will not be able to enroll through this view if they are already enrolled in the course """ CourseEnrollment.enroll(self.user, self.course.id) self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id)) # now try to enroll that student response = self._enroll_through_view(self.course) self.assertEqual(response.status_code, 400)
def test_locked_asset_registered(self): """ Test that locked assets behave appropriately in case user is logged in and registered for the course. """ CourseEnrollment.enroll(self.non_staff_usr, self.course_key) assert CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key) self.client.login(username=self.non_staff_usr, password='******') resp = self.client.get(self.url_locked) assert resp.status_code == 200
def test_unenroll(self, use_json): """ Test unenrolling a user. """ response = self.request_bulk_enroll( { 'identifiers': self.enrolled_student.email, 'action': 'unenroll', 'email_students': False, 'courses': self.course_key, }, use_json=use_json) assert response.status_code == 200 # test that the user is now unenrolled user = User.objects.get(email=self.enrolled_student.email) assert not CourseEnrollment.is_enrolled(user, self.course.id) # test the response data expected = { "action": "unenroll", "auto_enroll": False, "email_students": False, "courses": { self.course_key: { "action": "unenroll", "auto_enroll": False, "results": [{ "identifier": self.enrolled_student.email, "before": { "enrollment": True, "auto_enroll": False, "user": True, "allowed": False, }, "after": { "enrollment": False, "auto_enroll": False, "user": True, "allowed": False, } }] } } } manual_enrollments = ManualEnrollmentAudit.objects.all() assert manual_enrollments.count() == 1 assert manual_enrollments[0].state_transition == ENROLLED_TO_UNENROLLED res_json = json.loads(response.content.decode('utf-8')) assert res_json == expected # Check the outbox assert len(mail.outbox) == 0
def can_access_self_blocks(requesting_user: User, course_key: CourseKey) -> AccessResponse: """ Returns whether the requesting_user can access own blocks. """ user_is_enrolled_or_staff = ( # pylint: disable=consider-using-ternary (requesting_user.id and CourseEnrollment.is_enrolled(requesting_user, course_key)) or has_access(requesting_user, CourseStaffRole.ROLE, course_key) ) if user_is_enrolled_or_staff: return ACCESS_GRANTED return is_course_public(course_key)
def test_existing_inactive_enrollment(self): """ If the user has an inactive enrollment for the course, the view should behave as if the user has no enrollment. """ # Create an inactive enrollment CourseEnrollment.enroll(self.user, self.course.id) CourseEnrollment.unenroll(self.user, self.course.id, True) assert not CourseEnrollment.is_enrolled(self.user, self.course.id) assert get_enrollment(self.user.username, str(self.course.id)) is not None
def test_embargo_restrict(self): # When accessing the course from an embargoed country, # we should be blocked. with restrict_course(self.course.id) as redirect_url: response = self._change_enrollment('enroll') assert response.status_code == 200 assert response.content.decode('utf-8') == redirect_url # Verify that we weren't enrolled is_enrolled = CourseEnrollment.is_enrolled(self.user, self.course.id) assert not is_enrolled
def test_unenroll(self): # Enroll the student in the course CourseEnrollment.enroll(self.user, self.course.id, mode="honor") # Attempt to unenroll the student resp = self._change_enrollment('unenroll') self.assertEqual(resp.status_code, 200) # Expect that we're no longer enrolled self.assertFalse( CourseEnrollment.is_enrolled(self.user, self.course.id))
def test_user_is_not_unenrolled_on_failed_refund( self, mock_get_course_runs, mock_refund_entitlement, # pylint: disable=unused-argument mock_is_refundable # pylint: disable=unused-argument ): course_entitlement = CourseEntitlementFactory.create(user=self.user, mode=CourseMode.VERIFIED) mock_get_course_runs.return_value = self.return_values url = reverse( self.ENTITLEMENTS_ENROLLMENT_NAMESPACE, args=[str(course_entitlement.uuid)] ) assert course_entitlement.enrollment_course_run is None # Enroll the User data = { 'course_run_id': str(self.course.id) } response = self.client.post( url, data=json.dumps(data), content_type='application/json', ) course_entitlement.refresh_from_db() assert response.status_code == 201 assert CourseEnrollment.is_enrolled(self.user, self.course.id) # Unenroll with Revoke for refund revoke_url = url + '?is_refund=true' response = self.client.delete( revoke_url, content_type='application/json', ) assert response.status_code == 500 course_entitlement.refresh_from_db() assert CourseEnrollment.is_enrolled(self.user, self.course.id) assert course_entitlement.enrollment_course_run is not None assert course_entitlement.expired_at is None
def test_no_duplicate_emails_unenrolled_staff(self): """ Test that no duplicate emails are sent to a course staff that is not enrolled in the course, but is enrolled in other courses """ course_1 = CourseFactory.create() course_2 = CourseFactory.create() # make sure self.instructor isn't enrolled in the course assert not CourseEnrollment.is_enrolled(self.instructor, self.course.id) CourseEnrollment.enroll(self.instructor, course_1.id) CourseEnrollment.enroll(self.instructor, course_2.id) self.test_send_to_all()
def test_team_counter_get_teams_accessible_by_user(self, username, expected_count): user = self.users[username] try: organization_protection_status = teams_api.user_organization_protection_status( user, COURSE_KEY1) except ValueError: self.assertFalse(CourseEnrollment.is_enrolled(user, COURSE_KEY1)) return teams_query_set = teams_api.get_teams_accessible_by_user( user, [self.topic_id], COURSE_KEY1, organization_protection_status) self.assertEqual(expected_count, teams_query_set.count())
def test_team_counter_add_team_count(self, username, expected_team_count): user = self.users[username] try: organization_protection_status = teams_api.user_organization_protection_status( user, COURSE_KEY1) except ValueError: self.assertFalse(CourseEnrollment.is_enrolled(user, COURSE_KEY1)) return topic = {'id': self.topic_id} teams_api.add_team_count(user, [topic], COURSE_KEY1, organization_protection_status) self.assertEqual(expected_team_count, topic.get('team_count'))
def has_permission(self, request, view): course_key_string = view.kwargs.get('course_id') course_key = validate_course_key(course_key_string) if GlobalStaff().has_user(request.user): return True return ( CourseInstructorRole(course_key).has_user(request.user) or CourseStaffRole(course_key).has_user(request.user) or CourseEnrollment.is_enrolled(request.user, course_key) )
def test_has_specific_team_access_protected_team(self, username, expected_return): user = self.users[username] try: self.assertEqual( expected_return, teams_api.has_specific_team_access(user, self.team_protected_1)) except ValueError: self.assertFalse( CourseEnrollment.is_enrolled(user, self.team_protected_1.course_id))
def test_existing_active_enrollment(self): """ The view should respond with HTTP 409 if the user has an existing active enrollment for the course. """ # Enroll user in the course CourseEnrollment.enroll(self.user, self.course.id) assert CourseEnrollment.is_enrolled(self.user, self.course.id) response = self._post_to_view() assert response.status_code == 409 msg = Messages.ENROLLMENT_EXISTS.format(username=self.user.username, course_id=self.course.id) self.assertResponseMessage(response, msg)
def add_user(self, user): """Adds the given user to the CourseTeam.""" from lms.djangoapps.teams.api import user_protection_status_matches_team if not CourseEnrollment.is_enrolled(user, self.course_id): raise NotEnrolledInCourseForTeam if CourseTeamMembership.user_in_team_for_teamset( user, self.course_id, self.topic_id): raise AlreadyOnTeamInTeamset if not user_protection_status_matches_team(user, self): raise AddToIncompatibleTeamError return CourseTeamMembership.objects.create(user=user, team=self)
def test_existing_inactive_enrollment(self): """ If the user has an inactive enrollment for the course, the view should behave as if the user has no enrollment. """ # Create an inactive enrollment CourseEnrollment.enroll(self.user, self.course.id) CourseEnrollment.unenroll(self.user, self.course.id, True) self.assertFalse( CourseEnrollment.is_enrolled(self.user, self.course.id)) self.assertIsNotNone( get_enrollment(self.user.username, six.text_type(self.course.id)))
def test_enroll_with_email(self, use_json): """ Test enrolling using a username as the identifier. """ response = self.request_bulk_enroll({ 'identifiers': self.notenrolled_student.email, 'action': 'enroll', 'email_students': False, 'courses': self.course_key, }, use_json=use_json) self.assertEqual(response.status_code, 200) # test that the user is now enrolled user = User.objects.get(email=self.notenrolled_student.email) self.assertTrue(CourseEnrollment.is_enrolled(user, self.course.id)) # test the response data expected = { "action": "enroll", "auto_enroll": False, "email_students": False, "courses": { self.course_key: { "action": "enroll", "auto_enroll": False, "results": [ { "identifier": self.notenrolled_student.email, "before": { "enrollment": False, "auto_enroll": False, "user": True, "allowed": False, }, "after": { "enrollment": True, "auto_enroll": False, "user": True, "allowed": False, } } ] } } } manual_enrollments = ManualEnrollmentAudit.objects.all() self.assertEqual(manual_enrollments.count(), 1) self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED) res_json = json.loads(response.content.decode('utf-8')) self.assertEqual(res_json, expected) # Check the outbox self.assertEqual(len(mail.outbox), 0)
def test_user_forum_default_role_on_course_deletion(self): """ Test that a user enrolls and gets "Student" forum role for that course which he creates and remains enrolled even the course is deleted and keeps its "Student" forum role for that course """ # check that user has enrollment for this course self.assertTrue( CourseEnrollment.is_enrolled(self.user, self.course_key)) # check that user has his default "Student" forum role for this course self.assertTrue( self.user.roles.filter(name="Student", course_id=self.course_key)) delete_course(self.course_key, self.user.id) # check that user's enrollment for this course is not deleted self.assertTrue( CourseEnrollment.is_enrolled(self.user, self.course_key)) # check that user has forum role for this course even after deleting it self.assertTrue( self.user.roles.filter(name="Student", course_id=self.course_key))
def test_unenroll(self): # Enroll the user in the course CourseEnrollment.enroll(self.user, self.course.id, mode="honor") enrollment = data.update_course_enrollment(self.user.username, str(self.course.id), is_active=False) # Determine that the returned enrollment is inactive. assert not enrollment['is_active'] # Expect that we're no longer enrolled assert not CourseEnrollment.is_enrolled(self.user, self.course.id)
def test_user_can_revoke_and_refund(self, mock_course_uuid, mock_get_course_runs, mock_refund_entitlement): course_entitlement = CourseEntitlementFactory.create( user=self.user, mode=CourseMode.VERIFIED) mock_get_course_runs.return_value = self.return_values mock_course_uuid.return_value = course_entitlement.course_uuid url = reverse(self.ENTITLEMENTS_ENROLLMENT_NAMESPACE, args=[str(course_entitlement.uuid)]) assert course_entitlement.enrollment_course_run is None data = {'course_run_id': str(self.course.id)} response = self.client.post( url, data=json.dumps(data), content_type='application/json', ) course_entitlement.refresh_from_db() assert response.status_code == 201 assert CourseEnrollment.is_enrolled(self.user, self.course.id) # Unenroll with Revoke for refund revoke_url = url + '?is_refund=true' response = self.client.delete( revoke_url, content_type='application/json', ) assert response.status_code == 204 course_entitlement.refresh_from_db() assert mock_refund_entitlement.is_called assert mock_refund_entitlement.call_args[1][ 'course_entitlement'] == course_entitlement assert not CourseEnrollment.is_enrolled(self.user, self.course.id) assert course_entitlement.enrollment_course_run is None assert course_entitlement.expired_at is not None
def check_enrollment(user, course): """ Check if the course requires a learner to be enrolled for access. Returns: AccessResponse: Either ACCESS_GRANTED or EnrollmentRequiredAccessError. """ if check_public_access(course, [COURSE_VISIBILITY_PUBLIC]): return ACCESS_GRANTED if CourseEnrollment.is_enrolled(user, course.id): return ACCESS_GRANTED return EnrollmentRequiredAccessError()
def test_unenrollment_without_filter_configuration(self): """ Test usual unenrollment process without filter's intervention. Expected result: - CourseUnenrollmentStarted does not have any effect on the unenrollment process. - The unenrollment process ends successfully. """ CourseEnrollment.enroll(self.user, self.course.id, mode="audit") CourseEnrollment.unenroll(self.user, self.course.id) self.assertFalse( CourseEnrollment.is_enrolled(self.user, self.course.id))
def can_show_certificate_message(course, student, course_grade, certificates_enabled_for_course): """ Returns True if a course certificate message can be shown """ is_allowlisted = certs_api.is_on_allowlist(student, course.id) auto_cert_gen_enabled = auto_certificate_generation_enabled() has_active_enrollment = CourseEnrollment.is_enrolled(student, course.id) certificates_are_viewable = certs_api.certificates_viewable_for_course( course) return ((auto_cert_gen_enabled or certificates_enabled_for_course) and has_active_enrollment and certificates_are_viewable and (course_grade.passed or is_allowlisted))
def test_user_role_on_course_recreate(self): """ Test that creating same course again after deleting it gives user his default forum role "Student" for that course """ # check that user has enrollment and his default "Student" forum role for this course self.assertTrue( CourseEnrollment.is_enrolled(self.user, self.course_key)) self.assertTrue( self.user.roles.filter(name="Student", course_id=self.course_key)) # delete this course and recreate this course with same user delete_course(self.course_key, self.user.id) resp = self._create_course_with_given_location(self.course_key) self.assertEqual(resp.status_code, 200) # check that user has his enrollment for this course self.assertTrue( CourseEnrollment.is_enrolled(self.user, self.course_key)) # check that user has his default "Student" forum role for this course self.assertTrue( self.user.roles.filter(name="Student", course_id=self.course_key))
def test_unenroll_when_unenrollment_disabled(self): """ Tests that a user cannot unenroll when unenrollment has been disabled. """ # Enroll the student in the course CourseEnrollment.enroll(self.user, self.course.id, mode="honor") # Attempt to unenroll resp = self._change_enrollment('unenroll') assert resp.status_code == 400 # Verify that user is still enrolled is_enrolled = CourseEnrollment.is_enrolled(self.user, self.course.id) assert is_enrolled
def test_change_to_default_if_verified(self): """ Tests that a student that is a currently enrolled verified student cannot accidentally change their enrollment mode """ CourseEnrollment.enroll(self.user, self.course.id, mode='verified') assert CourseEnrollment.is_enrolled(self.user, self.course.id) # now try to enroll the student in the default mode: response = self._enroll_through_view(self.course) assert response.status_code == 400 enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user( self.user, self.course.id) assert is_active assert enrollment_mode == 'verified'
def test_start_flow(self): # Go to the course mode page, expecting a redirect to the intro step of the # payment flow (since this is a professional ed course). Otherwise, the student # would have the option to choose their track. resp = self.client.get(self.urls['course_modes_choose']) self.assertRedirects( resp, self.urls['verify_student_start_flow'], fetch_redirect_response=False, ) # For professional ed courses, expect that the student is NOT enrolled # automatically in the course. assert not CourseEnrollment.is_enrolled(self.user, self.course_key)
def generate_certificate_for_user(request): """ Generate certificates for a user. This is meant to be used by support staff through the UI in lms/djangoapps/support Arguments: request (HttpRequest): The request object Returns: HttpResponse Example Usage: POST /certificates/generate * username: "******" * course_key: "edX/DemoX/Demo_Course" Response: 200 OK """ # Check the POST parameters, returning a 400 response if they're not valid. params, response = _validate_post_params(request.POST) if response is not None: return response try: # Check that the course exists CourseOverview.get_from_id(params["course_key"]) except CourseOverview.DoesNotExist: msg = _("The course {course_key} does not exist").format( course_key=params["course_key"]) return HttpResponseBadRequest(msg) else: # Check that the user is enrolled in the course if not CourseEnrollment.is_enrolled(params["user"], params["course_key"]): msg = _( "User {username} is not enrolled in the course {course_key}" ).format(username=params["user"].username, course_key=params["course_key"]) return HttpResponseBadRequest(msg) # Attempt to generate certificate generate_certificates_for_students( request, params["course_key"], student_set="specific_student", specific_student_id=params["user"].id) return HttpResponse(200)
def get(self, request, *args, **kwargs): course_key_string = kwargs.get('course_key_string') course_key = CourseKey.from_string(course_key_string) if course_home_legacy_is_active(course_key): raise Http404 # Enable NR tracing for this view based on course monitoring_utils.set_custom_attribute('course_id', course_key_string) monitoring_utils.set_custom_attribute('user_id', request.user.id) monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False) is_staff = bool(has_access(request.user, 'staff', course_key)) _, request.user = setup_masquerade( request, course_key, staff_access=is_staff, reset_masquerade_data=True, ) # Record user activity for tracking progress towards a user's course goals (for mobile app) UserActivity.record_user_activity(request.user, course.id, request=request, only_if_mobile_app=True) if not CourseEnrollment.is_enrolled(request.user, course_key) and not is_staff: return Response('User not enrolled.', status=401) blocks = get_course_date_blocks(course, request.user, request, include_access=True, include_past_dates=True) learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, course_key=course_key, ) # User locale settings user_timezone_locale = user_timezone_locale_prefs(request) user_timezone = user_timezone_locale['user_timezone'] data = { 'has_ended': course.has_ended(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'learner_is_full_access': learner_is_full_access, 'user_timezone': user_timezone, } context = self.get_serializer_context() context['learner_is_full_access'] = learner_is_full_access serializer = self.get_serializer_class()(data, context=context) return Response(serializer.data)