def _complete_user_enrollment(): # pylint: disable=missing-docstring for enrollment in pending_enrollments: # EnterpriseCustomers may enroll users in courses before the users themselves # actually exist in the system; in such a case, the enrollment for each such # course is finalized when the user registers with the OpenEdX platform. enterprise_customer_user.enroll(enrollment.course_id, enrollment.course_mode, cohort=enrollment.cohort_name) track_enrollment('pending-admin-enrollment', user_instance.id, enrollment.course_id) pending_ecu.delete()
def save(self): # pylint: disable=arguments-differ """ Save the model with the found EnterpriseCustomerUser. """ course_id = self.validated_data['course_id'] __, created = models.EnterpriseCourseEnrollment.objects.get_or_create( enterprise_customer_user=self.enterprise_customer_user, course_id=course_id, ) if created: track_enrollment('rest-api-enrollment', self.enterprise_customer_user.user_id, course_id)
def handle_user_post_save(sender, **kwargs): # pylint: disable=unused-argument """ Handle User model changes - checks if pending enterprise customer user record exists and upgrades it to actual link. If there are pending enrollments attached to the PendingEnterpriseCustomerUser, then this signal also takes the newly-created users and enrolls them in the relevant courses. """ created = kwargs.get("created", False) user_instance = kwargs.get("instance", None) if user_instance is None: return # should never happen, but better safe than 500 error try: pending_ecu = PendingEnterpriseCustomerUser.objects.get( user_email=user_instance.email) except PendingEnterpriseCustomerUser.DoesNotExist: return # nothing to do in this case if not created: # existing user changed his email to match one of pending link records - try linking him to EC try: existing_record = EnterpriseCustomerUser.objects.get( user_id=user_instance.id) message_template = "User {user} have changed email to match pending Enterprise Customer link, " \ "but was already linked to Enterprise Customer {enterprise_customer} - " \ "deleting pending link record" logger.info( message_template.format( user=user_instance, enterprise_customer=existing_record.enterprise_customer)) pending_ecu.delete() return except EnterpriseCustomerUser.DoesNotExist: pass # everything ok - current user is not linked to other ECs enterprise_customer_user = EnterpriseCustomerUser.objects.create( enterprise_customer=pending_ecu.enterprise_customer, user_id=user_instance.id) for enrollment in pending_ecu.pendingenrollment_set.all(): # EnterpriseCustomers may enroll users in courses before the users themselves # actually exist in the system; in such a case, the enrollment for each such # course is finalized when the user registers with the OpenEdX platform. enrollment.complete_enrollment() EnterpriseCourseEnrollment.objects.create( enterprise_customer_user=enterprise_customer_user, course_id=enrollment.course_id, ) track_enrollment('pending-admin-enrollment', user_instance.id, enrollment.course_id) pending_ecu.delete()
def create(self, validated_data): """ Perform the enrollment for existing enterprise customer users, or create the pending objects for new users. """ enterprise_customer = self.context.get('enterprise_customer') lms_user = validated_data.get('lms_user_id') tpa_user = validated_data.get('tpa_user_id') user_email = validated_data.get('user_email') course_run_id = validated_data.get('course_run_id') course_mode = validated_data.get('course_mode') cohort = validated_data.get('cohort') email_students = validated_data.get('email_students') is_active = validated_data.get('is_active') enterprise_customer_user = lms_user or tpa_user or user_email if isinstance(enterprise_customer_user, models.EnterpriseCustomerUser): validated_data[ 'enterprise_customer_user'] = enterprise_customer_user try: if is_active: enterprise_customer_user.enroll(course_run_id, course_mode, cohort=cohort) else: enterprise_customer_user.unenroll(course_run_id) except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError, HttpClientError) as exc: validated_data['detail'] = str(exc) return validated_data if is_active: track_enrollment('enterprise-customer-enrollment-api', enterprise_customer_user.user_id, course_run_id) else: if is_active: enterprise_customer_user = enterprise_customer.enroll_user_pending_registration( user_email, course_mode, course_run_id, cohort=cohort) else: enterprise_customer.clear_pending_registration( user_email, course_run_id) if email_students: enterprise_customer.notify_enrolled_learners( self.context.get('request_user'), course_run_id, [enterprise_customer_user]) validated_data['detail'] = 'success' return validated_data
def test_track_enrollment(self, track_event_mock): """ ``track_enrollment`` invokes ``track_event`` with custom properties. """ pathway = 'some-pathway' user_id = 123123 course_run_id = 'course-v1:Some+edX+Course' url_path = '/some/url/path' utils.track_enrollment(pathway, user_id, course_run_id, url_path) track_event_mock.assert_called_once_with( user_id, 'edx.bi.user.enterprise.onboarding', { 'pathway': pathway, 'url_path': url_path, 'course_run_id': course_run_id, })
def enroll_user(cls, enterprise_customer, user, course_mode, *course_ids): """ Enroll a single user in any number of courses using a particular course mode. Args: enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment user: The user who needs to be enrolled in the course course_mode: The mode with which the enrollment should be created *course_ids: An iterable containing any number of course IDs to eventually enroll the user in. Returns: Boolean: Whether or not enrollment succeeded for all courses specified """ enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create( enterprise_customer=enterprise_customer, user_id=user.id) enrollment_client = EnrollmentApiClient() succeeded = True for course_id in course_ids: try: enrollment_client.enroll_user_in_course( user.username, course_id, course_mode) except HttpClientError as exc: # Check if user is already enrolled then we should ignore exception if cls.is_user_enrolled(user, course_id, course_mode): succeeded = True else: succeeded = False default_message = 'No error message provided' try: error_message = json.loads(exc.content.decode()).get( 'message', default_message) except ValueError: error_message = default_message logging.error( 'Error while enrolling user %(user)s: %(message)s', dict(user=user.username, message=error_message)) if succeeded: __, created = EnterpriseCourseEnrollment.objects.get_or_create( enterprise_customer_user=enterprise_customer_user, course_id=course_id, defaults={ 'source': EnterpriseEnrollmentSource.get_source( EnterpriseEnrollmentSource.MANUAL) }) if created: track_enrollment('admin-enrollment', user.id, course_id) return succeeded
def _complete_user_enrollment(): """ Complete an Enterprise User's enrollment. EnterpriseCustomers may enroll users in courses before the users themselves actually exist in the system; in such a case, the enrollment for each such course is finalized when the user registers with the OpenEdX platform. """ for enrollment in pending_enrollments: enterprise_customer_user.enroll(enrollment.course_id, enrollment.course_mode, cohort=enrollment.cohort_name, source_slug=getattr( enrollment.source, 'slug', None)) track_enrollment('pending-admin-enrollment', user_instance.id, enrollment.course_id) pending_ecu.delete()
def create(self, validated_data): """ Perform the enrollment for existing enterprise customer users, or create the pending objects for new users. """ enterprise_customer = self.context.get('enterprise_customer') lms_user = validated_data.get('lms_user_id') tpa_user = validated_data.get('tpa_user_id') user_email = validated_data.get('user_email') course_run_id = validated_data.get('course_run_id') course_mode = validated_data.get('course_mode') cohort = validated_data.get('cohort') email_students = validated_data.get('email_students') is_active = validated_data.get('is_active') enterprise_customer_user = lms_user or tpa_user or user_email if isinstance(enterprise_customer_user, models.EnterpriseCustomerUser): validated_data['enterprise_customer_user'] = enterprise_customer_user try: if is_active: enterprise_customer_user.enroll( course_run_id, course_mode, cohort=cohort, source_slug=models.EnterpriseEnrollmentSource.API ) else: enterprise_customer_user.unenroll(course_run_id) except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError, HttpClientError) as exc: error_message = ( '[Enterprise API] An exception occurred while enrolling the user.' ' EnterpriseCustomer: {enterprise_customer}, LmsUser: {lms_user}, TpaUser: {tpa_user},' ' UserEmail: {user_email}, CourseRun: {course_run_id}, CourseMode {course_mode}, Message: {exc}.' ).format( enterprise_customer=enterprise_customer, lms_user=lms_user, tpa_user=tpa_user, user_email=user_email, course_run_id=course_run_id, course_mode=course_mode, exc=str(exc) ) LOGGER.error(error_message) validated_data['detail'] = str(exc) return validated_data if is_active: track_enrollment('enterprise-customer-enrollment-api', enterprise_customer_user.user_id, course_run_id) else: if is_active: enterprise_customer_user = enterprise_customer.enroll_user_pending_registration( user_email, course_mode, course_run_id, cohort=cohort, enrollment_source=models.EnterpriseEnrollmentSource.get_source( models.EnterpriseEnrollmentSource.API ) ) else: enterprise_customer.clear_pending_registration(user_email, course_run_id) if email_students: enterprise_customer.notify_enrolled_learners( self.context.get('request_user'), course_run_id, [enterprise_customer_user] ) validated_data['detail'] = 'success' return validated_data
def create(self, validated_data): """ Perform the enrollment for existing enterprise customer users, or create the pending objects for new users. """ enterprise_customer = self.context.get('enterprise_customer') lms_user = validated_data.get('lms_user_id') tpa_user = validated_data.get('tpa_user_id') user_email = validated_data.get('user_email') course_run_id = validated_data.get('course_run_id') course_mode = validated_data.get('course_mode') cohort = validated_data.get('cohort') email_students = validated_data.get('email_students') is_active = validated_data.get('is_active') discount = enterprise_customer.default_contract_discount or 0 LOGGER.info( "[Enrollment-API] Received a call with the following parameters. lms_user: [{lms_user}], " "tpa_user: [{tpa_user}], user_email: {user_email}, course_run_id: {course_run_id}, " "course_mode: {course_mode}, is_active: {is_active}, discount: {discount}" .format( lms_user=lms_user.id if lms_user else None, tpa_user=tpa_user.id if tpa_user else None, user_email=user_email.id if isinstance( user_email, models.EnterpriseCustomerUser) else user_email, course_run_id=course_run_id, course_mode=course_mode, is_active=is_active, discount=discount)) enterprise_customer_user = lms_user or tpa_user or user_email if isinstance(enterprise_customer_user, models.EnterpriseCustomerUser): validated_data[ 'enterprise_customer_user'] = enterprise_customer_user try: if is_active: LOGGER.info( "[Enrollment-API] Enrolling the enterprise learner [{learner_id}] in course [{course_run_id}] " "in [{course_mode}] mode".format( learner_id=enterprise_customer_user.id, course_run_id=course_run_id, course_mode=course_mode)) enterprise_customer_user.enroll( course_run_id, course_mode, cohort=cohort, source_slug=models.EnterpriseEnrollmentSource.API, discount_percentage=discount) else: LOGGER.info( "[Enrollment-API] Un-enrolling the enterprise learner [{learner_id}] in course " "[{course_run_id}]".format( learner_id=enterprise_customer_user.id, course_run_id=course_run_id, )) enterprise_customer_user.unenroll(course_run_id) except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError, HttpClientError) as exc: error_message = ( '[Enterprise API] An exception occurred while enrolling the user.' ' EnterpriseCustomer: {enterprise_customer}, LmsUser: {lms_user}, TpaUser: {tpa_user},' ' UserEmail: {user_email}, CourseRun: {course_run_id}, CourseMode {course_mode}, Message: {exc}.' ).format(enterprise_customer=enterprise_customer, lms_user=lms_user, tpa_user=tpa_user, user_email=user_email, course_run_id=course_run_id, course_mode=course_mode, exc=str(exc)) LOGGER.error(error_message) validated_data['detail'] = str(exc) return validated_data if is_active: track_enrollment('enterprise-customer-enrollment-api', enterprise_customer_user.user_id, course_run_id) else: if is_active: LOGGER.info( "[Enrollment-API] Creating the pending enrollment for [{email}] in course [{course_run_id}] " "in [{course_mode}] mode".format( email=user_email, course_run_id=course_run_id, course_mode=course_mode)) enterprise_customer_user = enterprise_customer.enroll_user_pending_registration( user_email, course_mode, course_run_id, cohort=cohort, enrollment_source=models.EnterpriseEnrollmentSource. get_source(models.EnterpriseEnrollmentSource.API), discount=discount) else: LOGGER.info( "[Enrollment-API] Removing the pending enrollment for [{email}] in course [{course_run_id}]" .format(email=user_email, course_run_id=course_run_id)) enterprise_customer.clear_pending_registration( user_email, course_run_id) if email_students: enterprise_customer.notify_enrolled_learners( self.context.get('request_user'), course_run_id, [enterprise_customer_user]) validated_data['detail'] = 'success' LOGGER.info( "[Enrollment-API] Returning success for a call with the following parameters. lms_user: [{lms_user}], " "tpa_user: [{tpa_user}], user_email: {user_email}, course_run_id: {course_run_id}, " "course_mode: {course_mode}, is_active: {is_active}".format( lms_user=lms_user.id if lms_user else None, tpa_user=tpa_user.id if tpa_user else None, user_email=user_email.id if isinstance( user_email, models.EnterpriseCustomerUser) else user_email, course_run_id=course_run_id, course_mode=course_mode, is_active=is_active)) return validated_data