Exemple #1
0
 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()
Exemple #2
0
    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()
Exemple #4
0
    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
Exemple #5
0
 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,
         })
Exemple #6
0
    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
Exemple #9
0
    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