@classmethod<EOL><INDENT>def enroll_user(cls, enterprise_customer, user, course_mode, *course_ids):<DEDENT>

enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=user.id<EOL>)<EOL>enrollment_client = EnrollmentApiClient()<EOL>succeeded = True<EOL>for course_id in course_ids:<EOL><INDENT>try:<EOL><INDENT>enrollment_client.enroll_user_in_course(user.username, course_id, course_mode)<EOL><DEDENT>except HttpClientError as exc:<EOL><INDENT>if cls.is_user_enrolled(user, course_id, course_mode):<EOL><INDENT>succeeded = True<EOL><DEDENT>else:<EOL><INDENT>succeeded = False<EOL>default_message = '<STR_LIT>'<EOL>try:<EOL><INDENT>error_message = json.loads(exc.content.decode()).get('<STR_LIT:message>', default_message)<EOL><DEDENT>except ValueError:<EOL><INDENT>error_message = default_message<EOL><DEDENT>logging.error(<EOL>'<STR_LIT>',<EOL>dict(user=user.username, message=error_message)<EOL>)<EOL><DEDENT><DEDENT>if succeeded:<EOL><INDENT>__, created = EnterpriseCourseEnrollment.objects.get_or_create(<EOL>enterprise_customer_user=enterprise_customer_user,<EOL>course_id=course_id<EOL>)<EOL>if created:<EOL><INDENT>track_enrollment('<STR_LIT>', user.id, course_id)<EOL><DEDENT><DEDENT><DEDENT>return succeeded<EOL>

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


@classmethod<EOL><INDENT>def is_user_enrolled(cls, user, course_id, course_mode):<DEDENT>

enrollment_client = EnrollmentApiClient()<EOL>try:<EOL><INDENT>enrollments = enrollment_client.get_course_enrollment(user.username, course_id)<EOL>if enrollments and course_mode == enrollments.get('<STR_LIT>'):<EOL><INDENT>return True<EOL><DEDENT><DEDENT>except HttpClientError as exc:<EOL><INDENT>logging.error(<EOL>'<STR_LIT>',<EOL>dict(user=user.username, message=str(exc))<EOL>)<EOL><DEDENT>except KeyError as exc:<EOL><INDENT>logging.warning(<EOL>'<STR_LIT>',<EOL>dict(user=user.username, message=str(exc))<EOL>)<EOL><DEDENT>return False<EOL>

Query the enrollment API and determine if a learner is enrolled in a given course run track.

Args:
    user: The user whose enrollment needs to be checked
    course_mode: The mode with which the enrollment should be checked
    course_id: course id of the course where enrollment should be checked.

Returns:
    Boolean: Whether or not enrollment exists


users = User.objects.filter(email__in=emails)<EOL>present_emails = users.values_list('<STR_LIT:email>', flat=True)<EOL>missing_emails = list(set(emails) - set(present_emails))<EOL>return users, missing_emails<EOL>

Accept a list of emails, and separate them into users that exist on OpenEdX and users who don't.

Args:
    emails: An iterable of email addresses to split between existing and nonexisting

Returns:
    users: Queryset of users who exist in the OpenEdX platform and who were in the list of email addresses
    missing_emails: List of unique emails which were in the original list, but do not yet exist as users


@classmethod<EOL><INDENT>def enroll_users_in_program(cls, enterprise_customer, program_details, course_mode, emails, cohort=None):<DEDENT>

existing_users, unregistered_emails = cls.get_users_by_email(emails)<EOL>course_ids = get_course_runs_from_program(program_details)<EOL>successes = []<EOL>pending = []<EOL>failures = []<EOL>for user in existing_users:<EOL><INDENT>succeeded = cls.enroll_user(enterprise_customer, user, course_mode, *course_ids)<EOL>if succeeded:<EOL><INDENT>successes.append(user)<EOL><DEDENT>else:<EOL><INDENT>failures.append(user)<EOL><DEDENT><DEDENT>for email in unregistered_emails:<EOL><INDENT>pending_user = enterprise_customer.enroll_user_pending_registration(<EOL>email,<EOL>course_mode,<EOL>*course_ids,<EOL>cohort=cohort<EOL>)<EOL>pending.append(pending_user)<EOL><DEDENT>return successes, pending, failures<EOL>

Enroll existing users in all courses in a program, and create pending enrollments for nonexisting users.

Args:
    enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment
    program_details: The details of the program in which we're enrolling
    course_mode (str): The mode with which we're enrolling in the program
    emails: An iterable of email addresses which need to be enrolled

Returns:
    successes: A list of users who were successfully enrolled in all courses of the program
    pending: A list of PendingEnterpriseCustomerUsers who were successfully linked and had
        pending enrollments created for them in the database
    failures: A list of users who could not be enrolled in the program


@classmethod<EOL><INDENT>def enroll_users_in_course(cls, enterprise_customer, course_id, course_mode, emails):<DEDENT>

existing_users, unregistered_emails = cls.get_users_by_email(emails)<EOL>successes = []<EOL>pending = []<EOL>failures = []<EOL>for user in existing_users:<EOL><INDENT>succeeded = cls.enroll_user(enterprise_customer, user, course_mode, course_id)<EOL>if succeeded:<EOL><INDENT>successes.append(user)<EOL><DEDENT>else:<EOL><INDENT>failures.append(user)<EOL><DEDENT><DEDENT>for email in unregistered_emails:<EOL><INDENT>pending_user = enterprise_customer.enroll_user_pending_registration(<EOL>email,<EOL>course_mode,<EOL>course_id<EOL>)<EOL>pending.append(pending_user)<EOL><DEDENT>return successes, pending, failures<EOL>

Enroll existing users in a course, and create a pending enrollment for nonexisting users.

Args:
    enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment
    course_id (str): The unique identifier of the course in which we're enrolling
    course_mode (str): The mode with which we're enrolling in the course
    emails: An iterable of email addresses which need to be enrolled

Returns:
    successes: A list of users who were successfully enrolled in the course
    pending: A list of PendingEnterpriseCustomerUsers who were successfully linked and had
        pending enrollments created for them in the database
    failures: A list of users who could not be enrolled in the course


@classmethod<EOL><INDENT>def send_messages(cls, http_request, message_requests):<DEDENT>

deduplicated_messages = set(message_requests)<EOL>for msg_type, text in deduplicated_messages:<EOL><INDENT>message_function = getattr(messages, msg_type)<EOL>message_function(http_request, text)<EOL><DEDENT>

Deduplicate any outgoing message requests, and send the remainder.

Args:
    http_request: The HTTP request in whose response we want to embed the messages
    message_requests: A list of undeduplicated messages in the form of tuples of message type
        and text- for example, ('error', 'Something went wrong')


@classmethod<EOL><INDENT>def notify_program_learners(cls, enterprise_customer, program_details, users):<DEDENT>

program_name = program_details.get('<STR_LIT:title>')<EOL>program_branding = program_details.get('<STR_LIT:type>')<EOL>program_uuid = program_details.get('<STR_LIT>')<EOL>lms_root_url = get_configuration_value_for_site(<EOL>enterprise_customer.site,<EOL>'<STR_LIT>',<EOL>settings.LMS_ROOT_URL<EOL>)<EOL>program_path = urlquote(<EOL>'<STR_LIT>'.format(<EOL>program_uuid=program_uuid,<EOL>tpa_hint=enterprise_customer.identity_provider,<EOL>)<EOL>)<EOL>destination_url = '<STR_LIT>'.format(<EOL>site=lms_root_url,<EOL>login_or_register='<STR_LIT>',<EOL>program_path=program_path<EOL>)<EOL>program_type = '<STR_LIT>'<EOL>program_start = get_earliest_start_date_from_program(program_details)<EOL>with mail.get_connection() as email_conn:<EOL><INDENT>for user in users:<EOL><INDENT>login_or_register = '<STR_LIT>' if isinstance(user, PendingEnterpriseCustomerUser) else '<STR_LIT>'<EOL>destination_url = destination_url.format(login_or_register=login_or_register)<EOL>send_email_notification_message(<EOL>user=user,<EOL>enrolled_in={<EOL>'<STR_LIT:name>': program_name,<EOL>'<STR_LIT:url>': destination_url,<EOL>'<STR_LIT:type>': program_type,<EOL>'<STR_LIT:start>': program_start,<EOL>'<STR_LIT>': program_branding,<EOL>},<EOL>enterprise_customer=enterprise_customer,<EOL>email_connection=email_conn<EOL>)<EOL><DEDENT><DEDENT>

Notify learners about a program in which they've been enrolled.

Args:
    enterprise_customer: The EnterpriseCustomer being linked to
    program_details: Details about the specific program the learners were enrolled in
    users: An iterable of the users or pending users who were enrolled


@classmethod<EOL><INDENT>def get_success_enrollment_message(cls, users, enrolled_in):<DEDENT>

Create message for the users who were enrolled in a course or program.

Args:
    users: An iterable of users who were successfully enrolled
    enrolled_in (str): A string identifier for the course or program the users were enrolled in

Returns:
    tuple: A 2-tuple containing a message type and message text


@classmethod<EOL><INDENT>def get_failed_enrollment_message(cls, users, enrolled_in):<DEDENT>

failed_emails = [user.email for user in users]<EOL>return (<EOL>'<STR_LIT:error>',<EOL>_(<EOL>'<STR_LIT>'<EOL>).format(<EOL>enrolled_in=enrolled_in,<EOL>user_list='<STR_LIT:U+002CU+0020>'.join(failed_emails),<EOL>)<EOL>)<EOL>

Create message for the users who were not able to be enrolled in a course or program.

Args:
    users: An iterable of users who were not successfully enrolled
    enrolled_in (str): A string identifier for the course or program with which enrollment was attempted

Returns:
tuple: A 2-tuple containing a message type and message text


@classmethod<EOL><INDENT>def get_pending_enrollment_message(cls, pending_users, enrolled_in):<DEDENT>

pending_emails = [pending_user.user_email for pending_user in pending_users]<EOL>return (<EOL>'<STR_LIT>',<EOL>_(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(<EOL>platform_name=settings.PLATFORM_NAME,<EOL>enrolled_in=enrolled_in,<EOL>pending_email_list='<STR_LIT:U+002CU+0020>'.join(pending_emails),<EOL>)<EOL>)<EOL>

Create message for the users who were enrolled in a course or program.

Args:
    users: An iterable of PendingEnterpriseCustomerUsers who were successfully linked with a pending enrollment
    enrolled_in (str): A string identifier for the course or program the pending users were linked to

Returns:
    tuple: A 2-tuple containing a message type and message text


pending_messages = []<EOL>if course_id:<EOL><INDENT>succeeded, pending, failed = cls.enroll_users_in_course(<EOL>enterprise_customer=enterprise_customer,<EOL>course_id=course_id,<EOL>course_mode=mode,<EOL>emails=emails,<EOL>)<EOL>all_successes = succeeded + pending<EOL>if notify:<EOL><INDENT>enterprise_customer.notify_enrolled_learners(<EOL>catalog_api_user=request.user,<EOL>course_id=course_id,<EOL>users=all_successes,<EOL>)<EOL><DEDENT>if succeeded:<EOL><INDENT>pending_messages.append(cls.get_success_enrollment_message(succeeded, course_id))<EOL><DEDENT>if failed:<EOL><INDENT>pending_messages.append(cls.get_failed_enrollment_message(failed, course_id))<EOL><DEDENT>if pending:<EOL><INDENT>pending_messages.append(cls.get_pending_enrollment_message(pending, course_id))<EOL><DEDENT><DEDENT>if program_details:<EOL><INDENT>succeeded, pending, failed = cls.enroll_users_in_program(<EOL>enterprise_customer=enterprise_customer,<EOL>program_details=program_details,<EOL>course_mode=mode,<EOL>emails=emails,<EOL>)<EOL>all_successes = succeeded + pending<EOL>if notify:<EOL><INDENT>cls.notify_program_learners(<EOL>enterprise_customer=enterprise_customer,<EOL>program_details=program_details,<EOL>users=all_successes<EOL>)<EOL><DEDENT>program_identifier = program_details.get('<STR_LIT:title>', program_details.get('<STR_LIT>', _('<STR_LIT>')))<EOL>if succeeded:<EOL><INDENT>pending_messages.append(cls.get_success_enrollment_message(succeeded, program_identifier))<EOL><DEDENT>if failed:<EOL><INDENT>pending_messages.append(cls.get_failed_enrollment_message(failed, program_identifier))<EOL><DEDENT>if pending:<EOL><INDENT>pending_messages.append(cls.get_pending_enrollment_message(pending, program_identifier))<EOL><DEDENT><DEDENT>cls.send_messages(request, pending_messages)<EOL>

Enroll the users with the given email addresses to the courses specified, either specifically or by program.

Args:
    cls (type): The EnterpriseCustomerManageLearnersView class itself
    request: The HTTP request the enrollment is being created by
    enterprise_customer: The instance of EnterpriseCustomer whose attached users we're enrolling
    emails: An iterable of strings containing email addresses to enroll in a course
    mode: The enrollment mode the users will be enrolled in the course with
    course_id: The ID of the course in which we want to enroll
    program_details: Details about a program in which we want to enroll
    notify: Whether to notify (by email) the users that have been enrolled


context = self._build_context(request, customer_uuid)<EOL>manage_learners_form = ManageLearnersForm(<EOL>user=request.user,<EOL>enterprise_customer=context[self.ContextParameters.ENTERPRISE_CUSTOMER]<EOL>)<EOL>context.update({self.ContextParameters.MANAGE_LEARNERS_FORM: manage_learners_form})<EOL>return render(request, self.template, context)<EOL>

Handle GET request - render linked learners list and "Link learner" form.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    customer_uuid (str): Enterprise Customer UUID

Returns:
    django.http.response.HttpResponse: HttpResponse


enterprise_customer = EnterpriseCustomer.objects.get(uuid=customer_uuid)  <EOL>manage_learners_form = ManageLearnersForm(<EOL>request.POST,<EOL>request.FILES,<EOL>user=request.user,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL>if manage_learners_form.is_valid():<EOL><INDENT>email_field_as_bulk_input = split_usernames_and_emails(<EOL>manage_learners_form.cleaned_data[ManageLearnersForm.Fields.EMAIL_OR_USERNAME]<EOL>)<EOL>is_bulk_entry = len(email_field_as_bulk_input) > <NUM_LIT:1><EOL>mode = manage_learners_form.cleaned_data[ManageLearnersForm.Fields.MODE]<EOL>if mode == ManageLearnersForm.Modes.MODE_SINGULAR and not is_bulk_entry:<EOL><INDENT>linked_learners = self._handle_singular(enterprise_customer, manage_learners_form)<EOL><DEDENT>elif mode == ManageLearnersForm.Modes.MODE_SINGULAR:<EOL><INDENT>linked_learners = self._handle_bulk_upload(<EOL>enterprise_customer,<EOL>manage_learners_form,<EOL>request,<EOL>email_list=email_field_as_bulk_input<EOL>)<EOL><DEDENT>else:<EOL><INDENT>linked_learners = self._handle_bulk_upload(enterprise_customer, manage_learners_form, request)<EOL><DEDENT><DEDENT>if manage_learners_form.is_valid():<EOL><INDENT>course_details = manage_learners_form.cleaned_data.get(ManageLearnersForm.Fields.COURSE)<EOL>program_details = manage_learners_form.cleaned_data.get(ManageLearnersForm.Fields.PROGRAM)<EOL>notification_type = manage_learners_form.cleaned_data.get(ManageLearnersForm.Fields.NOTIFY)<EOL>notify = notification_type == ManageLearnersForm.NotificationTypes.BY_EMAIL<EOL>course_id = None<EOL>if course_details:<EOL><INDENT>course_id = course_details['<STR_LIT>']<EOL><DEDENT>if course_id or program_details:<EOL><INDENT>course_mode = manage_learners_form.cleaned_data[ManageLearnersForm.Fields.COURSE_MODE]<EOL>self._enroll_users(<EOL>request=request,<EOL>enterprise_customer=enterprise_customer,<EOL>emails=linked_learners,<EOL>mode=course_mode,<EOL>course_id=course_id,<EOL>program_details=program_details,<EOL>notify=notify,<EOL>)<EOL><DEDENT>manage_learners_url = reverse("<STR_LIT>" + UrlNames.MANAGE_LEARNERS, args=(customer_uuid,))<EOL>search_keyword = self.get_search_keyword(request)<EOL>if search_keyword:<EOL><INDENT>manage_learners_url = manage_learners_url + "<STR_LIT>" + search_keyword<EOL><DEDENT>return HttpResponseRedirect(manage_learners_url)<EOL><DEDENT>context = self._build_context(request, customer_uuid)<EOL>context.update({self.ContextParameters.MANAGE_LEARNERS_FORM: manage_learners_form})<EOL>return render(request, self.template, context)<EOL>

Handle POST request - handle form submissions.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    customer_uuid (str): Enterprise Customer UUID

Returns:
    django.http.response.HttpResponse: HttpResponse


def delete(self, request, customer_uuid):

<EOL>enterprise_customer = EnterpriseCustomer.objects.get(uuid=customer_uuid)  <EOL>email_to_unlink = request.GET["<STR_LIT>"]<EOL>try:<EOL><INDENT>EnterpriseCustomerUser.objects.unlink_user(<EOL>enterprise_customer=enterprise_customer, user_email=email_to_unlink<EOL>)<EOL><DEDENT>except (EnterpriseCustomerUser.DoesNotExist, PendingEnterpriseCustomerUser.DoesNotExist):<EOL><INDENT>message = _("<STR_LIT>"<EOL>"<STR_LIT>").format(<EOL>email=email_to_unlink, ec_name=enterprise_customer.name)<EOL>return HttpResponse(message, content_type="<STR_LIT:application/json>", status=<NUM_LIT>)<EOL><DEDENT>return HttpResponse(<EOL>json.dumps({}),<EOL>content_type="<STR_LIT:application/json>"<EOL>)<EOL>

Handle DELETE request - handle unlinking learner.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    customer_uuid (str): Enterprise Customer UUID

Returns:
    django.http.response.HttpResponse: HttpResponse


user = kwargs.pop('<STR_LIT:user>', None)<EOL>self._user = user<EOL>self._enterprise_customer = kwargs.pop('<STR_LIT>', None)<EOL>super(ManageLearnersForm, self).__init__(*args, **kwargs)<EOL>

Initializes form: puts current user and enterprise_customer into a
field for later access.

Arguments:
    user (django.contrib.auth.models.User): current user
    enterprise_customer (enterprise.models.EnterpriseCustomer): current customer


email_or_username = self.cleaned_data[self.Fields.EMAIL_OR_USERNAME].strip()<EOL>if not email_or_username:<EOL><INDENT>return email_or_username<EOL><DEDENT>email = email_or_username__to__email(email_or_username)<EOL>bulk_entry = len(split_usernames_and_emails(email)) > <NUM_LIT:1><EOL>if bulk_entry:<EOL><INDENT>for email in split_usernames_and_emails(email):<EOL><INDENT>validate_email_to_link(<EOL>email,<EOL>None,<EOL>ValidationMessages.INVALID_EMAIL_OR_USERNAME,<EOL>ignore_existing=True<EOL>)<EOL><DEDENT>email = email_or_username<EOL><DEDENT>else:<EOL><INDENT>validate_email_to_link(<EOL>email,<EOL>email_or_username,<EOL>ValidationMessages.INVALID_EMAIL_OR_USERNAME,<EOL>ignore_existing=True<EOL>)<EOL><DEDENT>return email<EOL>

Clean email form field

Returns:
    str: the cleaned value, converted to an email address (or an empty string)


course_id = self.cleaned_data[self.Fields.COURSE].strip()<EOL>if not course_id:<EOL><INDENT>return None<EOL><DEDENT>try:<EOL><INDENT>client = EnrollmentApiClient()<EOL>return client.get_course_details(course_id)<EOL><DEDENT>except (HttpClientError, HttpServerError):<EOL><INDENT>raise ValidationError(ValidationMessages.INVALID_COURSE_ID.format(course_id=course_id))<EOL><DEDENT>

Verify course ID and retrieve course details.


program_id = self.cleaned_data[self.Fields.PROGRAM].strip()<EOL>if not program_id:<EOL><INDENT>return None<EOL><DEDENT>try:<EOL><INDENT>client = CourseCatalogApiClient(self._user, self._enterprise_customer.site)<EOL>program = client.get_program_by_uuid(program_id) or client.get_program_by_title(program_id)<EOL><DEDENT>except MultipleProgramMatchError as exc:<EOL><INDENT>raise ValidationError(ValidationMessages.MULTIPLE_PROGRAM_MATCH.format(program_count=exc.programs_matched))<EOL><DEDENT>except (HttpClientError, HttpServerError):<EOL><INDENT>raise ValidationError(ValidationMessages.INVALID_PROGRAM_ID.format(program_id=program_id))<EOL><DEDENT>if not program:<EOL><INDENT>raise ValidationError(ValidationMessages.INVALID_PROGRAM_ID.format(program_id=program_id))<EOL><DEDENT>if program['<STR_LIT:status>'] != ProgramStatuses.ACTIVE:<EOL><INDENT>raise ValidationError(<EOL>ValidationMessages.PROGRAM_IS_INACTIVE.format(program_id=program_id, status=program['<STR_LIT:status>'])<EOL>)<EOL><DEDENT>return program<EOL>

Clean program.

Try obtaining program treating form value as program UUID or title.

Returns:
    dict: Program information if program found


return self.cleaned_data.get(self.Fields.NOTIFY, self.NotificationTypes.DEFAULT)<EOL>


cleaned_data = super(ManageLearnersForm, self).clean()<EOL>email_or_username = self.data.get(self.Fields.EMAIL_OR_USERNAME, None)<EOL>bulk_upload_csv = self.files.get(self.Fields.BULK_UPLOAD, None)<EOL>if not email_or_username and not bulk_upload_csv:<EOL><INDENT>raise ValidationError(ValidationMessages.NO_FIELDS_SPECIFIED)<EOL><DEDENT>if email_or_username and bulk_upload_csv:<EOL><INDENT>raise ValidationError(ValidationMessages.BOTH_FIELDS_SPECIFIED)<EOL><DEDENT>if email_or_username:<EOL><INDENT>mode = self.Modes.MODE_SINGULAR<EOL><DEDENT>else:<EOL><INDENT>mode = self.Modes.MODE_BULK<EOL><DEDENT>cleaned_data[self.Fields.MODE] = mode<EOL>cleaned_data[self.Fields.NOTIFY] = self.clean_notify()<EOL>self._validate_course()<EOL>self._validate_program()<EOL>if self.data.get(self.Fields.PROGRAM, None) and self.data.get(self.Fields.COURSE, None):<EOL><INDENT>raise ValidationError(ValidationMessages.COURSE_AND_PROGRAM_ERROR)<EOL><DEDENT>return cleaned_data<EOL>

Clean fields that depend on each other.

In this case, the form can be used to link single user or bulk link multiple users. These are mutually
exclusive modes, so this method checks that only one field is passed.


<EOL>course_details = self.cleaned_data.get(self.Fields.COURSE)<EOL>if course_details:<EOL><INDENT>course_mode = self.cleaned_data.get(self.Fields.COURSE_MODE)<EOL>if not course_mode:<EOL><INDENT>raise ValidationError(ValidationMessages.COURSE_WITHOUT_COURSE_MODE)<EOL><DEDENT>valid_course_modes = course_details["<STR_LIT>"]<EOL>if all(course_mode != mode["<STR_LIT>"] for mode in valid_course_modes):<EOL><INDENT>error = ValidationError(ValidationMessages.COURSE_MODE_INVALID_FOR_COURSE.format(<EOL>course_mode=course_mode,<EOL>course_id=course_details["<STR_LIT>"],<EOL>))<EOL>raise ValidationError({self.Fields.COURSE_MODE: error})<EOL><DEDENT><DEDENT>

Verify that the selected mode is valid for the given course .


program = self.cleaned_data.get(self.Fields.PROGRAM)<EOL>if not program:<EOL><INDENT>return<EOL><DEDENT>course_runs = get_course_runs_from_program(program)<EOL>try:<EOL><INDENT>client = CourseCatalogApiClient(self._user, self._enterprise_customer.site)<EOL>available_modes = client.get_common_course_modes(course_runs)<EOL>course_mode = self.cleaned_data.get(self.Fields.COURSE_MODE)<EOL><DEDENT>except (HttpClientError, HttpServerError):<EOL><INDENT>raise ValidationError(<EOL>ValidationMessages.FAILED_TO_OBTAIN_COURSE_MODES.format(program_title=program.get("<STR_LIT:title>"))<EOL>)<EOL><DEDENT>if not course_mode:<EOL><INDENT>raise ValidationError(ValidationMessages.COURSE_WITHOUT_COURSE_MODE)<EOL><DEDENT>if course_mode not in available_modes:<EOL><INDENT>raise ValidationError(ValidationMessages.COURSE_MODE_NOT_AVAILABLE.format(<EOL>mode=course_mode, program_title=program.get("<STR_LIT:title>"), modes="<STR_LIT:U+002CU+0020>".join(available_modes)<EOL>))<EOL><DEDENT>

Verify that selected mode is available for program and all courses in the program


Initialize the form.

Substitute a ChoiceField in for the catalog field that would
normally be set up as a plain number entry field.


<EOL>if hasattr(self.instance, '<STR_LIT>'):<EOL><INDENT>catalog_api = CourseCatalogApiClient(self.user, self.instance.site)<EOL><DEDENT>else:<EOL><INDENT>catalog_api = CourseCatalogApiClient(self.user)<EOL><DEDENT>catalogs = catalog_api.get_all_catalogs()<EOL>catalogs = sorted(catalogs, key=lambda catalog: catalog.get('<STR_LIT:name>', '<STR_LIT>').lower())<EOL>return BLANK_CHOICE_DASH + [<EOL>(catalog['<STR_LIT:id>'], catalog['<STR_LIT:name>'],)<EOL>for catalog in catalogs<EOL>]<EOL>

Retrieve a list of catalog ID and name pairs.

Once retrieved, these name pairs can be used directly as a value
for the `choices` argument to a ChoiceField.


cleaned_data = super(EnterpriseCustomerAdminForm, self).clean()<EOL>if '<STR_LIT>' in cleaned_data and not cleaned_data['<STR_LIT>']:<EOL><INDENT>cleaned_data['<STR_LIT>'] = None<EOL><DEDENT>return cleaned_data<EOL>

Clean form fields prior to database entry.

In this case, the major cleaning operation is substituting a None value for a blank
value in the Catalog field.


super(EnterpriseCustomerIdentityProviderAdminForm, self).__init__(*args, **kwargs)<EOL>idp_choices = utils.get_idp_choices()<EOL>help_text = '<STR_LIT>'<EOL>if saml_provider_configuration:<EOL><INDENT>provider_id = self.instance.provider_id<EOL>url = reverse('<STR_LIT>'.format(<EOL>saml_provider_configuration._meta.app_label,<EOL>saml_provider_configuration._meta.model_name))<EOL>if provider_id:<EOL><INDENT>identity_provider = utils.get_identity_provider(provider_id)<EOL>if identity_provider:<EOL><INDENT>update_url = url + '<STR_LIT>'.format(identity_provider.pk)<EOL>help_text = '<STR_LIT>'.format(update_url=update_url, identity_provider=identity_provider.name)<EOL><DEDENT>else:<EOL><INDENT>help_text += '<STR_LIT>'<EOL><DEDENT><DEDENT>else:<EOL><INDENT>help_text += '<STR_LIT>''<STR_LIT>'.format(add_url=url)<EOL><DEDENT><DEDENT>if idp_choices is not None:<EOL><INDENT>self.fields['<STR_LIT>'] = forms.TypedChoiceField(<EOL>choices=idp_choices,<EOL>label=_('<STR_LIT>'),<EOL>help_text=mark_safe(help_text),<EOL>)<EOL><DEDENT>

Initialize the form.

Substitutes CharField with TypedChoiceField for the provider_id field.


super(EnterpriseCustomerIdentityProviderAdminForm, self).clean()<EOL>provider_id = self.cleaned_data.get('<STR_LIT>', None)<EOL>enterprise_customer = self.cleaned_data.get('<STR_LIT>', None)<EOL>if provider_id is None or enterprise_customer is None:<EOL><INDENT>return<EOL><DEDENT>identity_provider = utils.get_identity_provider(provider_id)<EOL>if not identity_provider:<EOL><INDENT>message = _(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>",<EOL>)<EOL>logger.exception(message)<EOL>raise ValidationError(message)<EOL><DEDENT>if identity_provider and identity_provider.site != enterprise_customer.site:<EOL><INDENT>raise ValidationError(<EOL>_(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(<EOL>enterprise_customer_site=enterprise_customer.site,<EOL>identity_provider_site=identity_provider.site,<EOL>),<EOL>)<EOL><DEDENT>

Final validations of model fields.

1. Validate that selected site for enterprise customer matches with the selected identity provider's site.


cleaned_data = super(EnterpriseCustomerReportingConfigAdminForm, self).clean()<EOL>report_customer = cleaned_data.get('<STR_LIT>')<EOL>invalid_catalogs = [<EOL>'<STR_LIT>'.format(catalog.title, catalog.uuid)<EOL>for catalog in cleaned_data.get('<STR_LIT>')<EOL>if catalog.enterprise_customer != report_customer<EOL>]<EOL>if invalid_catalogs:<EOL><INDENT>message = _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>',<EOL>).format(<EOL>enterprise_customer=report_customer,<EOL>invalid_catalogs=invalid_catalogs,<EOL>)<EOL>self.add_error('<STR_LIT>', message)<EOL><DEDENT>

Override of clean method to perform additional validation


Clean enterprise channel worker user form field

Returns:
    str: the cleaned value of channel user username for transmitting courses metadata.


if not instance.entitlement_id:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>return format_html(<EOL>'<STR_LIT>',<EOL>base_url=settings.ECOMMERCE_PUBLIC_URL_ROOT, id=instance.entitlement_id<EOL>)<EOL>

Instance is EnterpriseCustomer. Return e-commerce coupon urls.


return instance.enterprise_customer_entitlements.exists()<EOL>

Return True if provded enterprise customer has ecommerce coupons.

Arguments:
    instance (enterprise.models.EnterpriseCustomer): `EnterpriseCustomer` model instance


def get_form(self, request, obj=None, **kwargs):

form = super(EnterpriseCustomerAdmin, self).get_form(request, obj, **kwargs)<EOL>form.user = request.user<EOL>return form<EOL>

Retrieve the appropriate form to use, saving the request user
into the form for use in loading catalog details


return instance.enable_data_sharing_consent<EOL>

Return True if data sharing consent is enabled for EnterpriseCustomer.

Arguments:
    instance (enterprise.models.EnterpriseCustomer): `EnterpriseCustomer` model instance


has_logo = False<EOL>if hasattr(instance, '<STR_LIT>') and instance.branding_configuration.logo:<EOL><INDENT>has_logo = True<EOL><DEDENT>return has_logo<EOL>

Return True if EnterpriseCustomer has a logo.

Arguments:
    instance (enterprise.models.EnterpriseCustomer): `EnterpriseCustomer` model instance


return hasattr(instance, '<STR_LIT>')<EOL>

Return True if EnterpriseCustomer has related identity provider.

Arguments:
    instance (enterprise.models.EnterpriseCustomer): `EnterpriseCustomer` model instance


return instance.catalog is not None<EOL>

Return True if EnterpriseCustomer has catalog id with a link to catalog details page.

Arguments:
    instance (enterprise.models.EnterpriseCustomer): `EnterpriseCustomer` model instance


def manage_learners(self, request, obj):

<EOL>manage_learners_url = reverse("<STR_LIT>" + UrlNames.MANAGE_LEARNERS, args=(obj.uuid,))<EOL>return HttpResponseRedirect(manage_learners_url)<EOL>

Object tool handler method - redirects to "Manage Learners" view


def transmit_courses_metadata(self, request, obj):

<EOL>transmit_courses_metadata_url = reverse('<STR_LIT>' + UrlNames.TRANSMIT_COURSES_METADATA, args=(obj.uuid,))<EOL>return HttpResponseRedirect(transmit_courses_metadata_url)<EOL>

Object tool handler method - redirects to `Transmit Courses Metadata` view.


Returns the additional urls used by the custom object tools.


courses_string = mark_safe(self.get_enrolled_course_string(enterprise_customer_user))<EOL>return courses_string or '<STR_LIT:None>'<EOL>

Return a string representing the courses a given EnterpriseCustomerUser is enrolled in

Args:
    enterprise_customer_user: The instance of EnterpriseCustomerUser
        being rendered with this admin form.


def get_readonly_fields(self, request, obj=None):

readonly_fields = super(EnterpriseCustomerUserAdmin, self).get_readonly_fields(request, obj=obj)<EOL>if obj:  <EOL><INDENT>return readonly_fields + tuple(get_all_field_names(self.model))<EOL><DEDENT>return readonly_fields<EOL>

Make all fields readonly when editing existing model.


enrollment_client = EnrollmentApiClient()<EOL>enrolled_courses = enrollment_client.get_enrolled_courses(enterprise_customer_user.username)<EOL>course_details = []<EOL>courses_client = CourseApiClient()<EOL>for course in enrolled_courses:<EOL><INDENT>course_id = course['<STR_LIT>']['<STR_LIT>']<EOL>name = courses_client.get_course_details(course_id)['<STR_LIT:name>']<EOL>course_details.append({'<STR_LIT>': course_id, '<STR_LIT>': name})<EOL><DEDENT>template = '<STR_LIT>'<EOL>joiner = '<STR_LIT>'<EOL>return joiner.join(<EOL>template.format(<EOL>url=reverse('<STR_LIT>', args=[course['<STR_LIT>']]),<EOL>course_name=course['<STR_LIT>'],<EOL>)<EOL>for course in course_details<EOL>)<EOL>

Get an HTML string representing the courses the user is enrolled in.


preview_urls = [<EOL>url(<EOL>r"<STR_LIT>",<EOL>self.admin_site.admin_view(TemplatePreviewView.as_view()),<EOL>name=UrlNames.PREVIEW_EMAIL_TEMPLATE<EOL>)<EOL>]<EOL>return preview_urls + super(EnrollmentNotificationEmailTemplateAdmin, self).get_urls()<EOL>


<EOL>preview_url = reverse("<STR_LIT>" + UrlNames.PREVIEW_EMAIL_TEMPLATE, args=(obj.pk, preview_type))<EOL>return HttpResponseRedirect(preview_url)<EOL>

Object tool handler method - redirects to "Preview" view


def preview_as_course(self, request, obj):

return self.preview(obj, '<STR_LIT>')<EOL>

Redirect to preview the HTML template in the context of a course.


def preview_as_program(self, request, obj):

Redirect to preview the HTML template in the context of a program.


return False<EOL>

Disable add permission for EnterpriseCourseEnrollment.


def has_delete_permission(self, request, obj=None):

return False<EOL>

Disable deletion for EnterpriseCourseEnrollment.


return False<EOL>

Disable add permission for PendingEnrollment.


return False<EOL>


if CatalogIntegration is None:<EOL><INDENT>raise NotConnectedToOpenEdX(<EOL>_('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>)<EOL><DEDENT>discovery_root_url = CatalogIntegration.current().get_internal_api_url()<EOL>disc_url = '<STR_LIT>'.format(<EOL>discovery_root_url=discovery_root_url,<EOL>search_all_endpoint='<STR_LIT>',<EOL>query_string=urlencode(obj.content_filter, doseq=True)<EOL>)<EOL>return format_html(<EOL>'<STR_LIT>',<EOL>url=disc_url<EOL>)<EOL>


return format_html('<STR_LIT>'.format(uuid=obj.uuid))<EOL>


def get_fields(self, request, obj=None):

fields = list(super(EnterpriseCustomerReportingConfigurationAdmin, self).get_fields(request, obj))<EOL>if obj:<EOL><INDENT>return [f for f in fields if f not in {'<STR_LIT>', '<STR_LIT>'}]<EOL><DEDENT>return fields<EOL>

Return the fields that should be displayed on the admin form.


reader = unicodecsv.DictReader(file_stream, encoding="<STR_LIT:utf-8>")<EOL>if expected_columns and set(expected_columns) - set(reader.fieldnames):<EOL><INDENT>raise ValidationError(ValidationMessages.MISSING_EXPECTED_COLUMNS.format(<EOL>expected_columns="<STR_LIT:U+002CU+0020>".join(expected_columns), actual_columns="<STR_LIT:U+002CU+0020>".join(reader.fieldnames)<EOL>))<EOL><DEDENT>for row in reader:<EOL><INDENT>yield row<EOL><DEDENT>

Parse csv file and return a stream of dictionaries representing each row.

First line of CSV file must contain column headers.

Arguments:
     file_stream: input file
     expected_columns (set[unicode]): columns that are expected to be present

Yields:
    dict: CSV line parsed into a dictionary.


try:<EOL><INDENT>user = User.objects.get(username=email_or_username)<EOL>return user.email<EOL><DEDENT>except User.DoesNotExist:<EOL><INDENT>return email_or_username<EOL><DEDENT>

Convert email_or_username to email.

Returns:
    str: If `email_or_username` was a username returns user's email, otherwise assumes it was an email and returns
         as is.


def validate_email_to_link(email, raw_email=None, message_template=None, ignore_existing=False):

raw_email = raw_email if raw_email is not None else email<EOL>message_template = message_template if message_template is not None else ValidationMessages.INVALID_EMAIL<EOL>try:<EOL><INDENT>validate_email(email)<EOL><DEDENT>except ValidationError:<EOL><INDENT>raise ValidationError(message_template.format(argument=raw_email))<EOL><DEDENT>existing_record = EnterpriseCustomerUser.objects.get_link_by_email(email)<EOL>if existing_record and not ignore_existing:<EOL><INDENT>raise ValidationError(ValidationMessages.USER_ALREADY_REGISTERED.format(<EOL>email=email, ec_name=existing_record.enterprise_customer.name<EOL>))<EOL><DEDENT>return existing_record or False<EOL>

Validate email to be linked to Enterprise Customer.

Performs two checks:
    * Checks that email is valid
    * Checks that it is not already linked to any Enterprise Customer

Arguments:
    email (str): user email to link
    raw_email (str): raw value as it was passed by user - used in error message.
    message_template (str): Validation error template string.
    ignore_existing (bool): If True to skip the check for an existing Enterprise Customer

Raises:
    ValidationError: if email is invalid or already linked to Enterprise Customer.

Returns:
    bool: Whether or not there is an existing record with the same email address.


course_runs = set()<EOL>for course in program.get("<STR_LIT>", []):<EOL><INDENT>for run in course.get("<STR_LIT>", []):<EOL><INDENT>if "<STR_LIT:key>" in run and run["<STR_LIT:key>"]:<EOL><INDENT>course_runs.add(run["<STR_LIT:key>"])<EOL><DEDENT><DEDENT><DEDENT>return course_runs<EOL>

Return course runs from program data.

Arguments:
    program(dict): Program data from Course Catalog API

Returns:
    set: course runs in given program


start_dates = []<EOL>for course in program.get('<STR_LIT>', []):<EOL><INDENT>for run in course.get('<STR_LIT>', []):<EOL><INDENT>if run.get('<STR_LIT:start>'):<EOL><INDENT>start_dates.append(parse_lms_api_datetime(run['<STR_LIT:start>']))<EOL><DEDENT><DEDENT><DEDENT>if not start_dates:<EOL><INDENT>return None<EOL><DEDENT>return min(start_dates)<EOL>

Get the earliest date that one of the courses in the program was available.
For the sake of emails to new learners, we treat this as the program start date.

Arguemnts:
    program (dict): Program data from Course Catalog API

returns:
    datetime.datetime: The date and time at which the first course started


return [name.strip() for name in email_field.split('<STR_LIT:U+002C>')]<EOL>

Split the contents of the email field into a list.

In some cases, a user could enter a comma-separated value inline in the
Manage Learners form. We should check to see if that's the case, and
provide a list of email addresses or usernames if it is.


def paginated_list(object_list, page, page_size=<NUM_LIT>):

paginator = CustomPaginator(object_list, page_size)<EOL>try:<EOL><INDENT>object_list = paginator.page(page)<EOL><DEDENT>except PageNotAnInteger:<EOL><INDENT>object_list = paginator.page(<NUM_LIT:1>)<EOL><DEDENT>except EmptyPage:<EOL><INDENT>object_list = paginator.page(paginator.num_pages)<EOL><DEDENT>page_range = []<EOL>page_num = object_list.number<EOL>if paginator.num_pages <= <NUM_LIT:10>:<EOL><INDENT>page_range = range(paginator.num_pages)<EOL><DEDENT>else:<EOL><INDENT>if page_num > (PAGES_ON_EACH_SIDE + PAGES_ON_ENDS + <NUM_LIT:1>):<EOL><INDENT>page_range.extend(range(<NUM_LIT:1>, PAGES_ON_ENDS + <NUM_LIT:1>))<EOL>page_range.append(DOT)<EOL>page_range.extend(range(page_num - PAGES_ON_EACH_SIDE, page_num + <NUM_LIT:1>))<EOL><DEDENT>else:<EOL><INDENT>page_range.extend(range(<NUM_LIT:1>, page_num + <NUM_LIT:1>))<EOL><DEDENT>if page_num < (paginator.num_pages - PAGES_ON_EACH_SIDE - PAGES_ON_ENDS):<EOL><INDENT>page_range.extend(range(page_num + <NUM_LIT:1>, page_num + PAGES_ON_EACH_SIDE + <NUM_LIT:1>))<EOL>page_range.append(DOT)<EOL>page_range.extend(range(paginator.num_pages + <NUM_LIT:1> - PAGES_ON_ENDS, paginator.num_pages + <NUM_LIT:1>))<EOL><DEDENT>else:<EOL><INDENT>page_range.extend(range(page_num + <NUM_LIT:1>, paginator.num_pages + <NUM_LIT:1>))<EOL><DEDENT>object_list.paginator.page_range = page_range<EOL><DEDENT>return object_list<EOL>

Returns paginated list.

Arguments:
    object_list (QuerySet): A list of records to be paginated.
    page (int): Current page number.
    page_size (int): Number of records displayed in each paginated set.
    show_all (bool): Whether to show all records.

Adopted from django/contrib/admin/templatetags/admin_list.py
https://github.com/django/django/blob/1.11.1/django/contrib/admin/templatetags/admin_list.py#L50


def export_as_csv_action(description="<STR_LIT>", fields=None, header=True):

<EOL>def export_as_csv(modeladmin, request, queryset):  <EOL><INDENT>"""<STR_LIT>"""<EOL>opts = modeladmin.model._meta<EOL>if not fields:<EOL><INDENT>field_names = [field.name for field in opts.fields]<EOL><DEDENT>else:<EOL><INDENT>field_names = fields<EOL><DEDENT>response = HttpResponse(content_type="<STR_LIT>")<EOL>response["<STR_LIT>"] = "<STR_LIT>".format(<EOL>filename=str(opts).replace("<STR_LIT:.>", "<STR_LIT:_>")<EOL>)<EOL>writer = unicodecsv.writer(response, encoding="<STR_LIT:utf-8>")<EOL>if header:<EOL><INDENT>writer.writerow(field_names)<EOL><DEDENT>for obj in queryset:<EOL><INDENT>row = []<EOL>for field_name in field_names:<EOL><INDENT>field = getattr(obj, field_name)<EOL>if callable(field):<EOL><INDENT>value = field()<EOL><DEDENT>else:<EOL><INDENT>value = field<EOL><DEDENT>if value is None:<EOL><INDENT>row.append("<STR_LIT>")<EOL><DEDENT>elif not value and isinstance(value, string_types):<EOL><INDENT>row.append("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>row.append(value)<EOL><DEDENT><DEDENT>writer.writerow(row)<EOL><DEDENT>return response<EOL><DEDENT>export_as_csv.short_description = description<EOL>return export_as_csv<EOL>

Return an export csv action.

Arguments:
    description (string): action description
    fields ([string]): list of model fields to include
    header (bool): whether or not to output the column names as the first row


description = description or _("<STR_LIT>")<EOL>def clear_catalog_id(modeladmin, request, queryset):  <EOL><INDENT>"""<STR_LIT>"""<EOL>queryset.update(catalog=None)<EOL><DEDENT>clear_catalog_id.short_description = description<EOL>return clear_catalog_id<EOL>

Return the action method to clear the catalog ID for a EnterpriseCustomer.


return self._page_range or list(range(<NUM_LIT:1>, self.num_pages + <NUM_LIT:1>))<EOL>

We have customized the getter so that it can return the value of the page_range property
instead of always calculating the result.


self._page_range = value<EOL>

We have introduced a setter method here, so as to set value for page_range property.
This was not present in Paginator class.


return apps.get_app_config("<STR_LIT>").get_model("<STR_LIT>")<EOL>

Return User model for django.contrib.auth.


from enterprise.signals import handle_user_post_save<EOL>from django.db.models.signals import pre_migrate, post_save<EOL>post_save.connect(handle_user_post_save, sender=self.auth_user_model, dispatch_uid=USER_POST_SAVE_DISPATCH_UID)<EOL>pre_migrate.connect(self._disconnect_user_post_save_for_migrations)<EOL>

Perform other one-time initialization steps.


def _disconnect_user_post_save_for_migrations(self, sender, **kwargs):

from django.db.models.signals import post_save<EOL>post_save.disconnect(sender=self.auth_user_model, dispatch_uid=USER_POST_SAVE_DISPATCH_UID)<EOL>

Handle pre_migrate signal - disconnect User post_save handler.


request = get_request_or_stub()<EOL>decoded_jwt = get_decoded_jwt_from_request(request)<EOL>return request_user_has_implicit_access_via_jwt(decoded_jwt, ENTERPRISE_DASHBOARD_ADMIN_ROLE)<EOL>

Check that if request user has implicit access to `ENTERPRISE_DASHBOARD_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


return user_has_access_via_database(<EOL>user,<EOL>ENTERPRISE_DASHBOARD_ADMIN_ROLE,<EOL>EnterpriseFeatureUserRoleAssignment<EOL>)<EOL>

Check that if request user has explicit access to `ENTERPRISE_DASHBOARD_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


request = get_request_or_stub()<EOL>decoded_jwt = get_decoded_jwt_from_request(request)<EOL>return request_user_has_implicit_access_via_jwt(decoded_jwt, ENTERPRISE_CATALOG_ADMIN_ROLE, obj)<EOL>

Check that if request user has implicit access to `ENTERPRISE_CATALOG_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


return user_has_access_via_database(<EOL>user,<EOL>ENTERPRISE_CATALOG_ADMIN_ROLE,<EOL>EnterpriseFeatureUserRoleAssignment,<EOL>obj<EOL>)<EOL>

Check that if request user has explicit access to `ENTERPRISE_CATALOG_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


request = get_request_or_stub()<EOL>decoded_jwt = get_decoded_jwt_from_request(request)<EOL>return request_user_has_implicit_access_via_jwt(decoded_jwt, ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE, obj)<EOL>

Check that if request user has implicit access to `ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


return user_has_access_via_database(<EOL>user,<EOL>ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE,<EOL>EnterpriseFeatureUserRoleAssignment,<EOL>obj<EOL>)<EOL>

Check that if request user has explicit access to `ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE` feature role.

Returns:
    boolean: whether the request user has access or not


return not waffle.switch_is_active(ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH)<EOL>

Temporary check for rbac based permissions being enabled.


def filter_queryset(self, request, queryset, view):

if not request.user.is_staff:<EOL><INDENT>filter_kwargs = {view.USER_ID_FILTER: request.user.id}<EOL>queryset = queryset.filter(**filter_kwargs)<EOL><DEDENT>return queryset<EOL>

Filter only for the user's ID if non-staff.


if request.user.is_staff:<EOL><INDENT>email = request.query_params.get('<STR_LIT:email>', None)<EOL>username = request.query_params.get('<STR_LIT:username>', None)<EOL>query_parameters = {}<EOL>if email:<EOL><INDENT>query_parameters.update(email=email)<EOL><DEDENT>if username:<EOL><INDENT>query_parameters.update(username=username)<EOL><DEDENT>if query_parameters:<EOL><INDENT>users = User.objects.filter(**query_parameters).values_list('<STR_LIT:id>', flat=True)<EOL>queryset = queryset.filter(user_id__in=users)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>queryset = queryset.filter(user_id=request.user.id)<EOL><DEDENT>return queryset<EOL>

Apply incoming filters only if user is staff. If not, only filter by user's ID.


def update_enterprise_courses(self, enterprise_customer, course_container_key='<STR_LIT>', **kwargs):

enterprise_context = {<EOL>'<STR_LIT>': enterprise_customer and enterprise_customer.identity_provider,<EOL>'<STR_LIT>': enterprise_customer and str(enterprise_customer.uuid),<EOL>}<EOL>enterprise_context.update(**kwargs)<EOL>courses = []<EOL>for course in self.data[course_container_key]:<EOL><INDENT>courses.append(<EOL>self.update_course(course, enterprise_customer, enterprise_context)<EOL>)<EOL><DEDENT>self.data[course_container_key] = courses<EOL>

This method adds enterprise-specific metadata for each course.

We are adding following field in all the courses.
    tpa_hint: a string for identifying Identity Provider.
    enterprise_id: the UUID of the enterprise
    **kwargs: any additional data one would like to add on a per-use basis.

Arguments:
    enterprise_customer: The customer whose data will be used to fill the enterprise context.
    course_container_key: The key used to find the container for courses in the serializer's data dictionary.


def update_course(self, course, enterprise_customer, enterprise_context):

course['<STR_LIT>'] = self.update_course_runs(<EOL>course_runs=course.get('<STR_LIT>') or [],<EOL>enterprise_customer=enterprise_customer,<EOL>enterprise_context=enterprise_context,<EOL>)<EOL>marketing_url = course.get('<STR_LIT>')<EOL>if marketing_url:<EOL><INDENT>query_parameters = dict(enterprise_context, **utils.get_enterprise_utm_context(enterprise_customer))<EOL>course.update({'<STR_LIT>': utils.update_query_parameters(marketing_url, query_parameters)})<EOL><DEDENT>course.update(enterprise_context)<EOL>return course<EOL>

Update course metadata of the given course and return updated course.

Arguments:
    course (dict): Course Metadata returned by course catalog API
    enterprise_customer (EnterpriseCustomer): enterprise customer instance.
    enterprise_context (dict): Enterprise context to be added to course runs and URLs..

Returns:
    (dict): Updated course metadata


def update_course_runs(self, course_runs, enterprise_customer, enterprise_context):

updated_course_runs = []<EOL>for course_run in course_runs:<EOL><INDENT>track_selection_url = utils.get_course_track_selection_url(<EOL>course_run=course_run,<EOL>query_parameters=dict(enterprise_context, **utils.get_enterprise_utm_context(enterprise_customer)),<EOL>)<EOL>enrollment_url = enterprise_customer.get_course_run_enrollment_url(course_run.get('<STR_LIT:key>'))<EOL>course_run.update({<EOL>'<STR_LIT>': enrollment_url,<EOL>'<STR_LIT>': track_selection_url,<EOL>})<EOL>marketing_url = course_run.get('<STR_LIT>')<EOL>if marketing_url:<EOL><INDENT>query_parameters = dict(enterprise_context, **utils.get_enterprise_utm_context(enterprise_customer))<EOL>course_run.update({'<STR_LIT>': utils.update_query_parameters(marketing_url, query_parameters)})<EOL><DEDENT>updated_course_runs.append(course_run)<EOL><DEDENT>return updated_course_runs<EOL>

Update Marketing urls in course metadata and return updated course.

Arguments:
    course_runs (list): List of course runs.
    enterprise_customer (EnterpriseCustomer): enterprise customer instance.
    enterprise_context (dict): The context to inject into URLs.

Returns:
    (dict): Dictionary containing updated course metadata.


pass<EOL>

Do not perform any operations for state changing requests.


def update(self, instance, validated_data):

pass<EOL>


return obj.enterprise_customer.slug<EOL>

Return the slug of the associated enterprise customer.


try:<EOL><INDENT>user = User.objects.get(username=value)<EOL><DEDENT>except User.DoesNotExist:<EOL><INDENT>raise serializers.ValidationError("<STR_LIT>")<EOL><DEDENT>try:<EOL><INDENT>enterprise_customer_user = models.EnterpriseCustomerUser.objects.get(user_id=user.pk)<EOL><DEDENT>except models.EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>raise serializers.ValidationError("<STR_LIT>")<EOL><DEDENT>self.enterprise_customer_user = enterprise_customer_user<EOL>return value<EOL>

Verify that the username has a matching user, and that the user has an associated EnterpriseCustomerUser.


course_id = self.validated_data['<STR_LIT>']<EOL>__, created = models.EnterpriseCourseEnrollment.objects.get_or_create(<EOL>enterprise_customer_user=self.enterprise_customer_user,<EOL>course_id=course_id,<EOL>)<EOL>if created:<EOL><INDENT>track_enrollment('<STR_LIT>', self.enterprise_customer_user.user_id, course_id)<EOL><DEDENT>

Save the model with the found EnterpriseCustomerUser.


request = self.context['<STR_LIT>']<EOL>enterprise_customer = instance.enterprise_customer<EOL>representation = super(EnterpriseCustomerCatalogDetailSerializer, self).to_representation(instance)<EOL>paginated_content = instance.get_paginated_content(request.GET)<EOL>count = paginated_content['<STR_LIT:count>']<EOL>search_results = paginated_content['<STR_LIT>']<EOL>for item in search_results:<EOL><INDENT>content_type = item['<STR_LIT>']<EOL>marketing_url = item.get('<STR_LIT>')<EOL>if marketing_url:<EOL><INDENT>item['<STR_LIT>'] = utils.update_query_parameters(<EOL>marketing_url, utils.get_enterprise_utm_context(enterprise_customer)<EOL>)<EOL><DEDENT>if content_type == '<STR_LIT>':<EOL><INDENT>item['<STR_LIT>'] = instance.get_course_enrollment_url(item['<STR_LIT:key>'])<EOL><DEDENT>if content_type == '<STR_LIT>':<EOL><INDENT>item['<STR_LIT>'] = instance.get_course_run_enrollment_url(item['<STR_LIT:key>'])<EOL><DEDENT>if content_type == '<STR_LIT>':<EOL><INDENT>item['<STR_LIT>'] = instance.get_program_enrollment_url(item['<STR_LIT>'])<EOL><DEDENT><DEDENT>previous_url = None<EOL>next_url = None<EOL>page = int(request.GET.get('<STR_LIT>', '<STR_LIT:1>'))<EOL>request_uri = request.build_absolute_uri()<EOL>if paginated_content['<STR_LIT>']:<EOL><INDENT>previous_url = utils.update_query_parameters(request_uri, {'<STR_LIT>': page - <NUM_LIT:1>})<EOL><DEDENT>if paginated_content['<STR_LIT>']:<EOL><INDENT>next_url = utils.update_query_parameters(request_uri, {'<STR_LIT>': page + <NUM_LIT:1>})<EOL><DEDENT>representation['<STR_LIT:count>'] = count<EOL>representation['<STR_LIT>'] = previous_url<EOL>representation['<STR_LIT>'] = next_url<EOL>representation['<STR_LIT>'] = search_results<EOL>return representation<EOL>

Serialize the EnterpriseCustomerCatalog object.

Arguments:
    instance (EnterpriseCustomerCatalog): The EnterpriseCustomerCatalog to serialize.

Returns:
    dict: The EnterpriseCustomerCatalog converted to a dict.


return [record.serialize() for record in obj.data_sharing_consent_records]<EOL>

Return serialization of EnterpriseCustomerUser.data_sharing_consent_records property.

Arguments:
    EnterpriseCustomerUser: The EnterpriseCustomerUser.

Returns:
    list of dict: The serialized DataSharingConsent records associated with the EnterpriseCustomerUser.


if obj.user:<EOL><INDENT>return [group.name for group in obj.user.groups.filter(name__in=ENTERPRISE_PERMISSION_GROUPS)]<EOL><DEDENT>return []<EOL>

Return the enterprise related django groups that this user is a part of.


try:<EOL><INDENT>self.user = User.objects.get(username=value)<EOL><DEDENT>except User.DoesNotExist:<EOL><INDENT>raise serializers.ValidationError("<STR_LIT>")<EOL><DEDENT>return value<EOL>

Verify that the username has a matching user.


enterprise_customer = self.validated_data['<STR_LIT>']<EOL>ecu = models.EnterpriseCustomerUser(<EOL>user_id=self.user.pk,<EOL>enterprise_customer=enterprise_customer,<EOL>)<EOL>ecu.save()<EOL>


updated_course = copy.deepcopy(instance)<EOL>enterprise_customer_catalog = self.context['<STR_LIT>']<EOL>updated_course['<STR_LIT>'] = enterprise_customer_catalog.get_course_enrollment_url(<EOL>updated_course['<STR_LIT:key>']<EOL>)<EOL>for course_run in updated_course['<STR_LIT>']:<EOL><INDENT>course_run['<STR_LIT>'] = enterprise_customer_catalog.get_course_run_enrollment_url(<EOL>course_run['<STR_LIT:key>']<EOL>)<EOL><DEDENT>return updated_course<EOL>

Return the updated course data dictionary.

Arguments:
    instance (dict): The course data.

Returns:
    dict: The updated course data.


updated_course_run = copy.deepcopy(instance)<EOL>enterprise_customer_catalog = self.context['<STR_LIT>']<EOL>updated_course_run['<STR_LIT>'] = enterprise_customer_catalog.get_course_run_enrollment_url(<EOL>updated_course_run['<STR_LIT:key>']<EOL>)<EOL>return updated_course_run<EOL>

Return the updated course run data dictionary.

Arguments:
    instance (dict): The course run data.

Returns:
    dict: The updated course run data.


updated_program = copy.deepcopy(instance)<EOL>enterprise_customer_catalog = self.context['<STR_LIT>']<EOL>updated_program['<STR_LIT>'] = enterprise_customer_catalog.get_program_enrollment_url(<EOL>updated_program['<STR_LIT>']<EOL>)<EOL>for course in updated_program['<STR_LIT>']:<EOL><INDENT>course['<STR_LIT>'] = enterprise_customer_catalog.get_course_enrollment_url(course['<STR_LIT:key>'])<EOL>for course_run in course['<STR_LIT>']:<EOL><INDENT>course_run['<STR_LIT>'] = enterprise_customer_catalog.get_course_run_enrollment_url(<EOL>course_run['<STR_LIT:key>']<EOL>)<EOL><DEDENT><DEDENT>return updated_program<EOL>

Return the updated program data dictionary.

Arguments:
    instance (dict): The program data.

Returns:
    dict: The updated program data.


if not isinstance(data, list):<EOL><INDENT>message = self.error_messages['<STR_LIT>'].format(<EOL>input_type=type(data).__name__<EOL>)<EOL>raise serializers.ValidationError({<EOL>api_settings.NON_FIELD_ERRORS_KEY: [message]<EOL>})<EOL><DEDENT>ret = []<EOL>for item in data:<EOL><INDENT>try:<EOL><INDENT>validated = self.child.run_validation(item)<EOL><DEDENT>except serializers.ValidationError as exc:<EOL><INDENT>ret.append(exc.detail)<EOL><DEDENT>else:<EOL><INDENT>ret.append(validated)<EOL><DEDENT><DEDENT>return ret<EOL>

This implements the same relevant logic as ListSerializer except that if one or more items fail validation,
processing for other items that did not fail will continue.


ret = []<EOL>for attrs in validated_data:<EOL><INDENT>if '<STR_LIT>' not in attrs and not any(isinstance(attrs[field], list) for field in attrs):<EOL><INDENT>ret.append(self.child.create(attrs))<EOL><DEDENT>else:<EOL><INDENT>ret.append(attrs)<EOL><DEDENT><DEDENT>return ret<EOL>

This selectively calls the child create method based on whether or not validation failed for each payload.


return [<EOL>self.child.to_representation(item) if '<STR_LIT>' in item else item for item in data<EOL>]<EOL>

This selectively calls to_representation on each result that was processed by create.


enterprise_customer = self.context.get('<STR_LIT>')<EOL>lms_user = validated_data.get('<STR_LIT>')<EOL>tpa_user = validated_data.get('<STR_LIT>')<EOL>user_email = validated_data.get('<STR_LIT>')<EOL>course_run_id = validated_data.get('<STR_LIT>')<EOL>course_mode = validated_data.get('<STR_LIT>')<EOL>cohort = validated_data.get('<STR_LIT>')<EOL>email_students = validated_data.get('<STR_LIT>')<EOL>is_active = validated_data.get('<STR_LIT>')<EOL>enterprise_customer_user = lms_user or tpa_user or user_email<EOL>if isinstance(enterprise_customer_user, models.EnterpriseCustomerUser):<EOL><INDENT>validated_data['<STR_LIT>'] = enterprise_customer_user<EOL>try:<EOL><INDENT>if is_active:<EOL><INDENT>enterprise_customer_user.enroll(course_run_id, course_mode, cohort=cohort)<EOL><DEDENT>else:<EOL><INDENT>enterprise_customer_user.unenroll(course_run_id)<EOL><DEDENT><DEDENT>except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError, HttpClientError) as exc:<EOL><INDENT>validated_data['<STR_LIT>'] = str(exc)<EOL>return validated_data<EOL><DEDENT>if is_active:<EOL><INDENT>track_enrollment('<STR_LIT>', enterprise_customer_user.user_id, course_run_id)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if is_active:<EOL><INDENT>enterprise_customer_user = enterprise_customer.enroll_user_pending_registration(<EOL>user_email,<EOL>course_mode,<EOL>course_run_id,<EOL>cohort=cohort<EOL>)<EOL><DEDENT>else:<EOL><INDENT>enterprise_customer.clear_pending_registration(user_email, course_run_id)<EOL><DEDENT><DEDENT>if email_students:<EOL><INDENT>enterprise_customer.notify_enrolled_learners(<EOL>self.context.get('<STR_LIT>'),<EOL>course_run_id,<EOL>[enterprise_customer_user]<EOL>)<EOL><DEDENT>validated_data['<STR_LIT>'] = '<STR_LIT:success>'<EOL>return validated_data<EOL>

Perform the enrollment for existing enterprise customer users, or create the pending objects for new users.


enterprise_customer = self.context.get('<STR_LIT>')<EOL>try:<EOL><INDENT>return models.EnterpriseCustomerUser.objects.get(<EOL>user_id=value,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL><DEDENT>except models.EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>pass<EOL><DEDENT>return None<EOL>

Validates the lms_user_id, if is given, to see if there is an existing EnterpriseCustomerUser for it.


enterprise_customer = self.context.get('<STR_LIT>')<EOL>try:<EOL><INDENT>tpa_client = ThirdPartyAuthApiClient()<EOL>username = tpa_client.get_username_from_remote_id(<EOL>enterprise_customer.identity_provider, value<EOL>)<EOL>user = User.objects.get(username=username)<EOL>return models.EnterpriseCustomerUser.objects.get(<EOL>user_id=user.id,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL><DEDENT>except (models.EnterpriseCustomerUser.DoesNotExist, User.DoesNotExist):<EOL><INDENT>pass<EOL><DEDENT>return None<EOL>

Validates the tpa_user_id, if is given, to see if there is an existing EnterpriseCustomerUser for it.

It first uses the third party auth api to find the associated username to do the lookup.


enterprise_customer = self.context.get('<STR_LIT>')<EOL>try:<EOL><INDENT>user = User.objects.get(email=value)<EOL>return models.EnterpriseCustomerUser.objects.get(<EOL>user_id=user.id,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL><DEDENT>except (models.EnterpriseCustomerUser.DoesNotExist, User.DoesNotExist):<EOL><INDENT>pass<EOL><DEDENT>return value<EOL>

Validates the user_email, if given, to see if an existing EnterpriseCustomerUser exists for it.

If it does not, it does not fail validation, unlike for the other field validation methods above.


enterprise_customer = self.context.get('<STR_LIT>')<EOL>if not enterprise_customer.catalog_contains_course(value):<EOL><INDENT>raise serializers.ValidationError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_run_id=value,<EOL>enterprise_customer=enterprise_customer.name,<EOL>)<EOL>)<EOL><DEDENT>return value<EOL>

Validates that the course run id is part of the Enterprise Customer's catalog.


lms_user_id = data.get('<STR_LIT>')<EOL>tpa_user_id = data.get('<STR_LIT>')<EOL>user_email = data.get('<STR_LIT>')<EOL>if not lms_user_id and not tpa_user_id and not user_email:<EOL><INDENT>raise serializers.ValidationError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>return data<EOL>

Validate that at least one of the user identifier fields has been passed in.


def ensure_data_exists(self, request, data, error_message=None):

if not data:<EOL><INDENT>error_message = (<EOL>error_message or "<STR_LIT>".format(request.get_full_path())<EOL>)<EOL>LOGGER.error(error_message)<EOL>raise NotFound(error_message)<EOL><DEDENT>

Ensure that the wrapped API client's response brings us valid data. If not, raise an error and log it.


@method_decorator(require_at_least_one_query_parameter('<STR_LIT>', '<STR_LIT>'))<EOL><INDENT>@detail_route()<EOL>@permission_required('<STR_LIT>', fn=lambda request, pk, course_run_ids, program_uuids: pk)<EOL>def contains_content_items(self, request, pk, course_run_ids, program_uuids):<DEDENT>

enterprise_customer = self.get_object()<EOL>course_run_ids = [unquote(quote_plus(course_run_id)) for course_run_id in course_run_ids]<EOL>contains_content_items = False<EOL>for catalog in enterprise_customer.enterprise_customer_catalogs.all():<EOL><INDENT>contains_course_runs = not course_run_ids or catalog.contains_courses(course_run_ids)<EOL>contains_program_uuids = not program_uuids or catalog.contains_programs(program_uuids)<EOL>if contains_course_runs and contains_program_uuids:<EOL><INDENT>contains_content_items = True<EOL>break<EOL><DEDENT><DEDENT>return Response({'<STR_LIT>': contains_content_items})<EOL>

Return whether or not the specified content is available to the EnterpriseCustomer.

Multiple course_run_ids and/or program_uuids query parameters can be sent to this view to check
for their existence in the EnterpriseCustomerCatalogs associated with this EnterpriseCustomer.
At least one course run key or program UUID value must be included in the request.


@detail_route()<EOL><INDENT>@permission_required('<STR_LIT>', fn=lambda request, pk: pk)<EOL>def courses(self, request, pk=None):  <DEDENT>

Retrieve the list of courses contained within the catalog linked to this enterprise.

Only courses with active course runs are returned. A course run is considered active if it is currently
open for enrollment, or will open in the future.


@detail_route(methods=['<STR_LIT>'], permission_classes=[<EOL>permissions.IsAuthenticated,<EOL>HasEnterpriseEnrollmentAPIAccess,<EOL>])<EOL><INDENT>@permission_required('<STR_LIT>', fn=lambda request, pk: pk)<EOL>def course_enrollments(self, request, pk):<DEDENT>

enterprise_customer = self.get_object()<EOL>serializer = serializers.EnterpriseCustomerCourseEnrollmentsSerializer(<EOL>data=request.data,<EOL>many=True,<EOL>context={<EOL>'<STR_LIT>': enterprise_customer,<EOL>'<STR_LIT>': request.user,<EOL>}<EOL>)<EOL>if serializer.is_valid():<EOL><INDENT>serializer.save()<EOL>return Response(serializer.data, status=HTTP_200_OK)<EOL><DEDENT>return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)<EOL>

Creates a course enrollment for an EnterpriseCustomerUser.


self.queryset = self.queryset.order_by('<STR_LIT:name>')<EOL>enterprise_id = self.request.query_params.get('<STR_LIT>', None)<EOL>enterprise_slug = self.request.query_params.get('<STR_LIT>', None)<EOL>enterprise_name = self.request.query_params.get('<STR_LIT>', None)<EOL>if enterprise_id is not None:<EOL><INDENT>self.queryset = self.queryset.filter(uuid=enterprise_id)<EOL><DEDENT>elif enterprise_slug is not None:<EOL><INDENT>self.queryset = self.queryset.filter(slug=enterprise_slug)<EOL><DEDENT>elif enterprise_name is not None:<EOL><INDENT>self.queryset = self.queryset.filter(name__icontains=enterprise_name)<EOL><DEDENT>return self.list(request, *args, **kwargs)<EOL>

Returns the list of enterprise customers the user has a specified group permission access to.


@list_route()<EOL><INDENT>@permission_required('<STR_LIT>')<EOL>def dashboard_list(self, request, *args, **kwargs):  <DEDENT>

Supports listing dashboard enterprises for edx-portal frontend.


if self.request.method in ('<STR_LIT:GET>', ):<EOL><INDENT>return serializers.EnterpriseCourseEnrollmentReadOnlySerializer<EOL><DEDENT>return serializers.EnterpriseCourseEnrollmentWriteSerializer<EOL>

Use a special serializer for any requests that aren't read-only.


if self.request.method in ('<STR_LIT:GET>', ):<EOL><INDENT>return serializers.EnterpriseCustomerUserReadOnlySerializer<EOL><DEDENT>return serializers.EnterpriseCustomerUserWriteSerializer<EOL>

Use a flat serializer for any requests that aren't read-only.


@detail_route()<EOL><INDENT>def entitlements(self, request, pk=None):  <DEDENT>

enterprise_customer_user = self.get_object()<EOL>instance = {"<STR_LIT>": enterprise_customer_user.entitlements}<EOL>serializer = serializers.EnterpriseCustomerUserEntitlementSerializer(instance, context={'<STR_LIT>': request})<EOL>return Response(serializer.data)<EOL>

Retrieve the list of entitlements available to this learner.

Only those entitlements are returned that satisfy enterprise customer's data sharing setting.

Arguments:
    request (HttpRequest): Reference to in-progress request instance.
    pk (Int): Primary key value of the selected enterprise learner.

Returns:
    (HttpResponse): Response object containing a list of learner's entitlements.


@method_decorator(require_at_least_one_query_parameter('<STR_LIT>', '<STR_LIT>'))<EOL><INDENT>@detail_route()<EOL>def contains_content_items(self, request, pk, course_run_ids, program_uuids):<DEDENT>

enterprise_customer_catalog = self.get_object()<EOL>course_run_ids = [unquote(quote_plus(course_run_id)) for course_run_id in course_run_ids]<EOL>contains_content_items = True<EOL>if course_run_ids:<EOL><INDENT>contains_content_items = enterprise_customer_catalog.contains_courses(course_run_ids)<EOL><DEDENT>if program_uuids:<EOL><INDENT>contains_content_items = (<EOL>contains_content_items and<EOL>enterprise_customer_catalog.contains_programs(program_uuids)<EOL>)<EOL><DEDENT>return Response({'<STR_LIT>': contains_content_items})<EOL>

Return whether or not the EnterpriseCustomerCatalog contains the specified content.

Multiple course_run_ids and/or program_uuids query parameters can be sent to this view to check
for their existence in the EnterpriseCustomerCatalog. At least one course run key
or program UUID value must be included in the request.


@detail_route(url_path='<STR_LIT>'.format(COURSE_KEY_URL_PATTERN))<EOL><INDENT>@permission_required(<EOL>'<STR_LIT>',<EOL>fn=lambda request, pk, course_key: get_enterprise_customer_from_catalog_id(pk))<EOL>def course_detail(self, request, pk, course_key):  <DEDENT>

enterprise_customer_catalog = self.get_object()<EOL>course = enterprise_customer_catalog.get_course(course_key)<EOL>if not course:<EOL><INDENT>raise Http404<EOL><DEDENT>context = self.get_serializer_context()<EOL>context['<STR_LIT>'] = enterprise_customer_catalog<EOL>serializer = serializers.CourseDetailSerializer(course, context=context)<EOL>return Response(serializer.data)<EOL>

Return the metadata for the specified course.

The course needs to be included in the specified EnterpriseCustomerCatalog
in order for metadata to be returned from this endpoint.


@detail_route(url_path='<STR_LIT>'.format(settings.COURSE_ID_PATTERN))<EOL><INDENT>@permission_required(<EOL>'<STR_LIT>',<EOL>fn=lambda request, pk, course_id: get_enterprise_customer_from_catalog_id(pk))<EOL>def course_run_detail(self, request, pk, course_id):  <DEDENT>

enterprise_customer_catalog = self.get_object()<EOL>course_run = enterprise_customer_catalog.get_course_run(course_id)<EOL>if not course_run:<EOL><INDENT>raise Http404<EOL><DEDENT>context = self.get_serializer_context()<EOL>context['<STR_LIT>'] = enterprise_customer_catalog<EOL>serializer = serializers.CourseRunDetailSerializer(course_run, context=context)<EOL>return Response(serializer.data)<EOL>

Return the metadata for the specified course run.

The course run needs to be included in the specified EnterpriseCustomerCatalog
in order for metadata to be returned from this endpoint.


@detail_route(url_path='<STR_LIT>')<EOL><INDENT>@permission_required(<EOL>'<STR_LIT>',<EOL>fn=lambda request, pk, program_uuid: get_enterprise_customer_from_catalog_id(pk))<EOL>def program_detail(self, request, pk, program_uuid):  <DEDENT>

enterprise_customer_catalog = self.get_object()<EOL>program = enterprise_customer_catalog.get_program(program_uuid)<EOL>if not program:<EOL><INDENT>raise Http404<EOL><DEDENT>context = self.get_serializer_context()<EOL>context['<STR_LIT>'] = enterprise_customer_catalog<EOL>serializer = serializers.ProgramDetailSerializer(program, context=context)<EOL>return Response(serializer.data)<EOL>

Return the metadata for the specified program.

The program needs to be included in the specified EnterpriseCustomerCatalog
in order for metadata to be returned from this endpoint.


catalog_api = CourseCatalogApiClient(request.user)<EOL>catalogs = catalog_api.get_paginated_catalogs(request.GET)<EOL>self.ensure_data_exists(request, catalogs)<EOL>serializer = serializers.ResponsePaginationSerializer(catalogs)<EOL>return get_paginated_response(serializer.data, request)<EOL>

DRF view to list all catalogs.

Arguments:
    request (HttpRequest): Current request

Returns:
    (Response): DRF response object containing course catalogs.


catalog_api = CourseCatalogApiClient(request.user)<EOL>catalog = catalog_api.get_catalog(pk)<EOL>self.ensure_data_exists(<EOL>request,<EOL>catalog,<EOL>error_message=(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(pk=pk)<EOL>)<EOL>)<EOL>serializer = self.serializer_class(catalog)<EOL>return Response(serializer.data)<EOL>

DRF view to get catalog details.

Arguments:
    request (HttpRequest): Current request
    pk (int): Course catalog identifier

Returns:
    (Response): DRF response object containing course catalogs.


@method_decorator(enterprise_customer_required)<EOL><INDENT>@detail_route()<EOL>def courses(self, request, enterprise_customer, pk=None):  <DEDENT>

catalog_api = CourseCatalogApiClient(request.user, enterprise_customer.site)<EOL>courses = catalog_api.get_paginated_catalog_courses(pk, request.GET)<EOL>self.ensure_data_exists(<EOL>request,<EOL>courses,<EOL>error_message=(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(endpoint=request.get_full_path())<EOL>)<EOL>)<EOL>serializer = serializers.EnterpriseCatalogCoursesReadOnlySerializer(courses)<EOL>serializer.update_enterprise_courses(enterprise_customer, catalog_id=pk)<EOL>return get_paginated_response(serializer.data, request)<EOL>

Retrieve the list of courses contained within this catalog.

Only courses with active course runs are returned. A course run is considered active if it is currently
open for enrollment, or will open in the future.


email = get_request_value(request, self.REQUIRED_PARAM_EMAIL, '<STR_LIT>')<EOL>enterprise_name = get_request_value(request, self.REQUIRED_PARAM_ENTERPRISE_NAME, '<STR_LIT>')<EOL>number_of_codes = get_request_value(request, self.OPTIONAL_PARAM_NUMBER_OF_CODES, '<STR_LIT>')<EOL>if not (email and enterprise_name):<EOL><INDENT>raise CodesAPIRequestError(<EOL>self.get_missing_params_message([<EOL>(self.REQUIRED_PARAM_EMAIL, bool(email)),<EOL>(self.REQUIRED_PARAM_ENTERPRISE_NAME, bool(enterprise_name)),<EOL>])<EOL>)<EOL><DEDENT>return email, enterprise_name, number_of_codes<EOL>

Gets ``email``, ``enterprise_name``, and ``number_of_codes``,
which are the relevant parameters for this API endpoint.

:param request: The request to this endpoint.
:return: The ``email``, ``enterprise_name``, and ``number_of_codes`` from the request.


params = '<STR_LIT:U+002CU+0020>'.join(name for name, present in parameter_state if not present)<EOL>return self.MISSING_REQUIRED_PARAMS_MSG.format(params)<EOL>

Get a user-friendly message indicating a missing parameter for the API endpoint.


try:<EOL><INDENT>email, enterprise_name, number_of_codes = self.get_required_query_params(request)<EOL><DEDENT>except CodesAPIRequestError as invalid_request:<EOL><INDENT>return Response({'<STR_LIT:error>': str(invalid_request)}, status=HTTP_400_BAD_REQUEST)<EOL><DEDENT>subject_line = _('<STR_LIT>').format(<EOL>token_enterprise_name=enterprise_name<EOL>)<EOL>msg_with_codes = _('<STR_LIT>'<EOL>'<STR_LIT>').format(<EOL>token_email=email,<EOL>token_enterprise_name=enterprise_name,<EOL>token_number_codes=number_of_codes)<EOL>msg_without_codes = _('<STR_LIT>'<EOL>'<STR_LIT>').format(<EOL>token_email=email,<EOL>token_enterprise_name=enterprise_name)<EOL>app_config = apps.get_app_config("<STR_LIT>")<EOL>from_email_address = app_config.customer_success_email<EOL>cs_email = app_config.customer_success_email<EOL>data = {<EOL>self.REQUIRED_PARAM_EMAIL: email,<EOL>self.REQUIRED_PARAM_ENTERPRISE_NAME: enterprise_name,<EOL>self.OPTIONAL_PARAM_NUMBER_OF_CODES: number_of_codes,<EOL>}<EOL>try:<EOL><INDENT>mail.send_mail(<EOL>subject_line,<EOL>msg_with_codes if number_of_codes else msg_without_codes,<EOL>from_email_address,<EOL>[cs_email],<EOL>fail_silently=False<EOL>)<EOL>return Response(data, status=HTTP_200_OK)<EOL><DEDENT>except SMTPException:<EOL><INDENT>error_message = _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>).format(<EOL>token_cs_email=cs_email,<EOL>token_email=email,<EOL>token_enterprise_name=enterprise_name<EOL>)<EOL>LOGGER.error(error_message)<EOL>return Response(<EOL>{'<STR_LIT:error>': str('<STR_LIT>')},<EOL>status=HTTP_500_INTERNAL_SERVER_ERROR<EOL>)<EOL><DEDENT>

POST /enterprise/api/v1/request_codes

Requires a JSON object of the following format:
>>> {
>>>     "email": "bob@alice.com",
>>>     "enterprise_name": "IBM",
>>>     "number_of_codes": "50"
>>> }

Keys:
*email*
    Email of the customer who has requested more codes.
*enterprise_name*
    The name of the enterprise requesting more codes.
*number_of_codes*
    The number of codes requested.


@wraps(view)<EOL>def wrapper(request, *args, **kwargs):<EOL><INDENT>"""<STR_LIT>"""<EOL>user = request.user<EOL>enterprise_customer = get_enterprise_customer_for_user(user)<EOL>if enterprise_customer:<EOL><INDENT>args = args + (enterprise_customer,)<EOL>return view(request, *args, **kwargs)<EOL><DEDENT>else:<EOL><INDENT>raise PermissionDenied(<EOL>'<STR_LIT>'.format(<EOL>username=user.username<EOL>)<EOL>)<EOL><DEDENT><DEDENT>return wrapper<EOL>

Ensure the user making the API request is associated with an EnterpriseCustomer.

This decorator attempts to find an EnterpriseCustomer associated with the requesting
user and passes that EnterpriseCustomer to the view as a parameter. It will return a
PermissionDenied error if an EnterpriseCustomer cannot be found.

Usage::
    @enterprise_customer_required()
    def my_view(request, enterprise_customer):
        # Some functionality ...

    OR

    class MyView(View):
        ...
        @method_decorator(enterprise_customer_required)
        def get(self, request, enterprise_customer):
            # Some functionality ...


def outer_wrapper(view):<EOL><INDENT>"""<STR_LIT>"""<EOL>@wraps(view)<EOL>def wrapper(request, *args, **kwargs):<EOL><INDENT>"""<STR_LIT>"""<EOL>requirement_satisfied = False<EOL>for query_parameter_name in query_parameter_names:<EOL><INDENT>query_parameter_values = request.query_params.getlist(query_parameter_name)<EOL>kwargs[query_parameter_name] = query_parameter_values<EOL>if query_parameter_values:<EOL><INDENT>requirement_satisfied = True<EOL><DEDENT><DEDENT>if not requirement_satisfied:<EOL><INDENT>raise ValidationError(<EOL>detail='<STR_LIT>'.format(<EOL>params='<STR_LIT:U+002CU+0020>'.join(query_parameter_names)<EOL>)<EOL>)<EOL><DEDENT>return view(request, *args, **kwargs)<EOL><DEDENT>return wrapper<EOL><DEDENT>return outer_wrapper<EOL>

Ensure at least one of the specified query parameters are included in the request.

This decorator checks for the existence of at least one of the specified query
parameters and passes the values as function parameters to the decorated view.
If none of the specified query parameters are included in the request, a
ValidationError is raised.

Usage::
    @require_at_least_one_query_parameter('program_uuids', 'course_run_ids')
    def my_view(request, program_uuids, course_run_ids):
        # Some functionality ...


def has_permission(self, request, view):

if waffle.switch_is_active(ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH):<EOL><INDENT>return True<EOL><DEDENT>return (<EOL>super(IsAdminUserOrInGroup, self).has_permission(request, view) or<EOL>request.user.groups.filter(name__in=self.ALLOWED_API_GROUPS).exists() or<EOL>request.user.groups.filter(name__in=request.query_params.getlist('<STR_LIT>')).exists()<EOL>)<EOL>

Returns True if the requesting user is either 'staff' or belong to specific group, False otherwise.
It will also check for group membership against a list of groups in the permissions query parameter.


self.ALLOWED_API_GROUPS = [u'<STR_LIT>', ]<EOL>

Initialize the class with a API_ALLOWED_GROUPS


url = urlparse(request.build_absolute_uri())._replace(query=None).geturl()<EOL>next_page = None<EOL>previous_page = None<EOL>if data['<STR_LIT>']:<EOL><INDENT>next_page = "<STR_LIT>".format(<EOL>base_url=url,<EOL>query_parameters=urlparse(data['<STR_LIT>']).query,<EOL>)<EOL>next_page = next_page.rstrip('<STR_LIT:?>')<EOL><DEDENT>if data['<STR_LIT>']:<EOL><INDENT>previous_page = "<STR_LIT>".format(<EOL>base_url=url,<EOL>query_parameters=urlparse(data['<STR_LIT>'] or "<STR_LIT>").query,<EOL>)<EOL>previous_page = previous_page.rstrip('<STR_LIT:?>')<EOL><DEDENT>return Response(OrderedDict([<EOL>('<STR_LIT:count>', data['<STR_LIT:count>']),<EOL>('<STR_LIT>', next_page),<EOL>('<STR_LIT>', previous_page),<EOL>('<STR_LIT>', data['<STR_LIT>'])<EOL>]))<EOL>

Update pagination links in course catalog data and return DRF Response.

Arguments:
    data (dict): Dictionary containing catalog courses.
    request (HttpRequest): Current request object.

Returns:
    (Response): DRF response object containing pagination links.


service_users = get_service_usernames()<EOL>if request.user.username in service_users:<EOL><INDENT>self.update_throttle_scope()<EOL><DEDENT>return super(ServiceUserThrottle, self).allow_request(request, view)<EOL>

Modify throttling for service users.

Updates throttling rate if the request is coming from the service user, and
defaults to UserRateThrottle's configured setting otherwise.

Updated throttling rate comes from `DEFAULT_THROTTLE_RATES` key in `REST_FRAMEWORK`
setting. service user throttling is specified in `DEFAULT_THROTTLE_RATES` by `service_user` key

Example Setting:
    ```
    REST_FRAMEWORK = {
        ...
        'DEFAULT_THROTTLE_RATES': {
            ...
            'service_user': '50/day'
        }
    }
    ```


self.scope = SERVICE_USER_SCOPE<EOL>self.rate = self.get_rate()<EOL>self.num_requests, self.duration = self.parse_rate(self.rate)<EOL>

Update throttle scope so that service user throttle rates are applied.


return {getattr(settings, username, None) for username in SERVICE_USERNAMES}<EOL>

Return the set of service usernames that are given extended permissions in the API.


Get the enterprise customer id given an enterprise customer catalog id.


Entry point for subclassed commands to add custom arguments.


return EnterpriseCustomerUser.objects.values('<STR_LIT>')<EOL>


def _get_enterprise_admin_users_batch(self, start, end):

LOGGER.info('<STR_LIT>', start, end)<EOL>return User.objects.filter(groups__name=ENTERPRISE_DATA_API_ACCESS_GROUP, is_staff=False)[start:end]<EOL>

Returns a batched queryset of User objects.


def _get_enterprise_operator_users_batch(self, start, end):

LOGGER.info('<STR_LIT>', start, end)<EOL>return User.objects.filter(groups__name=ENTERPRISE_DATA_API_ACCESS_GROUP, is_staff=True)[start:end]<EOL>


def _get_enterprise_customer_users_batch(self, start, end):

LOGGER.info('<STR_LIT>', start, end)<EOL>return User.objects.filter(pk__in=self._get_enterprise_customer_user_ids())[start:end]<EOL>

Returns a batched queryset of EnterpriseCustomerUser objects.


def _get_enterprise_enrollment_api_admin_users_batch(self, start, end):

LOGGER.info('<STR_LIT>', start, end)<EOL>return User.objects.filter(groups__name=ENTERPRISE_ENROLLMENT_API_ACCESS_GROUP, is_staff=False)[start:end]<EOL>


def _get_enterprise_catalog_admin_users_batch(self, start, end):

Application = apps.get_model(OAUTH2_PROVIDER_APPLICATION_MODEL)     <EOL>LOGGER.info('<STR_LIT>', start, end)<EOL>catalog_admin_user_ids = Application.objects.filter(<EOL>user_id__in=self._get_enterprise_customer_user_ids()<EOL>).exclude(name=EDX_ORG_NAME).values('<STR_LIT>')<EOL>return User.objects.filter(pk__in=catalog_admin_user_ids)[start:end]<EOL>


def _assign_enterprise_role_to_users(self, _get_batch_method, options, is_feature_role=False):

role_name = options['<STR_LIT>']<EOL>batch_limit = options['<STR_LIT>']<EOL>batch_sleep = options['<STR_LIT>']<EOL>batch_offset = options['<STR_LIT>']<EOL>current_batch_index = batch_offset<EOL>users_batch = _get_batch_method(<EOL>batch_offset,<EOL>batch_offset + batch_limit<EOL>)<EOL>role_class = SystemWideEnterpriseRole<EOL>role_assignment_class = SystemWideEnterpriseUserRoleAssignment<EOL>if is_feature_role:<EOL><INDENT>role_class = EnterpriseFeatureRole<EOL>role_assignment_class = EnterpriseFeatureUserRoleAssignment<EOL><DEDENT>enterprise_role = role_class.objects.get(name=role_name)<EOL>while users_batch.count() > <NUM_LIT:0>:<EOL><INDENT>for index, user in enumerate(users_batch):<EOL><INDENT>LOGGER.info(<EOL>'<STR_LIT>',<EOL>current_batch_index + index, user.id<EOL>)<EOL>role_assignment_class.objects.get_or_create(<EOL>user=user,<EOL>role=enterprise_role<EOL>)<EOL><DEDENT>sleep(batch_sleep)<EOL>current_batch_index += len(users_batch)<EOL>users_batch = _get_batch_method(<EOL>current_batch_index,<EOL>current_batch_index + batch_limit<EOL>)<EOL><DEDENT>


LOGGER.info('<STR_LIT>')<EOL>role = options['<STR_LIT>']<EOL>if role == ENTERPRISE_ADMIN_ROLE:<EOL><INDENT>self._assign_enterprise_role_to_users(self._get_enterprise_admin_users_batch, options)<EOL><DEDENT>elif role == ENTERPRISE_OPERATOR_ROLE:<EOL><INDENT>self._assign_enterprise_role_to_users(self._get_enterprise_operator_users_batch, options)<EOL><DEDENT>elif role == ENTERPRISE_LEARNER_ROLE:<EOL><INDENT>self._assign_enterprise_role_to_users(self._get_enterprise_customer_users_batch, options)<EOL><DEDENT>elif role == ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE:<EOL><INDENT>self._assign_enterprise_role_to_users(self._get_enterprise_enrollment_api_admin_users_batch, options, True)<EOL><DEDENT>elif role == ENTERPRISE_CATALOG_ADMIN_ROLE:<EOL><INDENT>self._assign_enterprise_role_to_users(self._get_enterprise_catalog_admin_users_batch, options, True)<EOL><DEDENT>else:<EOL><INDENT>raise CommandError('<STR_LIT>'.format(<EOL>admin=ENTERPRISE_ADMIN_ROLE,<EOL>learner=ENTERPRISE_LEARNER_ROLE<EOL>))<EOL><DEDENT>LOGGER.info('<STR_LIT>')<EOL>

Entry point for managment command execution.


query = '''<STR_LIT>'''<EOL>with connection.cursor() as cursor:<EOL><INDENT>if enterprise_customer_uuid:<EOL><INDENT>cursor.execute(<EOL>query.format(enterprise_customer_filter='<STR_LIT>'),<EOL>[enterprise_customer_uuid]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>cursor.execute(<EOL>query.format(enterprise_customer_filter='<STR_LIT>')<EOL>)<EOL><DEDENT>return self._dictfetchall(cursor)<EOL><DEDENT>

Return enterprise customer UUID/user_id/course_run_id triples which represent CourseEnrollment records
which do not have a matching EnterpriseCourseEnrollment record.

The query used below looks for CourseEnrollment records that are associated with enterprise
learners where the enrollment data is after the creation of the link between the learner
and the enterprise. It also excludes learners with edx.org email addresses in order to
filter out test users.


columns = [col[<NUM_LIT:0>] for col in cursor.description]<EOL>return [<EOL>dict(zip(columns, row))<EOL>for row in cursor.fetchall()<EOL>]<EOL>

Return all rows from a cursor as a dict.


sso_provider_id = request.GET.get('<STR_LIT>')<EOL>if pipeline:<EOL><INDENT>sso_provider_id = Registry.get_from_pipeline(pipeline).provider_id<EOL><DEDENT>return get_enterprise_customer_for_sso(sso_provider_id)<EOL>

Get the EnterpriseCustomer associated with a running pipeline.


try:<EOL><INDENT>return EnterpriseCustomer.objects.get(  <EOL>enterprise_customer_identity_provider__provider_id=sso_provider_id<EOL>)<EOL><DEDENT>except EnterpriseCustomer.DoesNotExist:<EOL><INDENT>return None<EOL><DEDENT>

Get the EnterpriseCustomer object tied to an identity provider.


@partial<EOL>def handle_enterprise_logistration(backend, user, **kwargs):

request = backend.strategy.request<EOL>enterprise_customer = get_enterprise_customer_for_running_pipeline(<EOL>request,<EOL>{<EOL>'<STR_LIT>': backend.name,<EOL>'<STR_LIT>': kwargs<EOL>}<EOL>)<EOL>if enterprise_customer is None:<EOL><INDENT>return<EOL><DEDENT>enterprise_customer_user, _ = EnterpriseCustomerUser.objects.update_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL>

Perform the linking of user in the process of logging to the Enterprise Customer.

Args:
    backend: The class handling the SSO interaction (SAML, OAuth, etc)
    user: The user object in the process of being logged in with
    **kwargs: Any remaining pipeline variables


user_social_auth = UserSocialAuth.objects.select_related('<STR_LIT:user>').filter(<EOL>user__username=tpa_username, provider=tpa_provider.backend_name<EOL>).first()<EOL>return user_social_auth.user if user_social_auth else None<EOL>

Find the LMS user from the LMS model `UserSocialAuth`.

Arguments:
    tpa_provider (third_party_auth.provider): third party auth provider object
    tpa_username (str): Username returned by the third party auth


try:<EOL><INDENT>from third_party_auth.provider import Registry   <EOL><DEDENT>except ImportError as exception:<EOL><INDENT>LOGGER.warning("<STR_LIT>")<EOL>LOGGER.warning(exception)<EOL>Registry = None  <EOL><DEDENT>try:<EOL><INDENT>return Registry and Registry.get(provider_id)<EOL><DEDENT>except ValueError:<EOL><INDENT>return None<EOL><DEDENT>

Get Identity Provider with given id.

Return:
    Instance of ProviderConfig or None.


try:<EOL><INDENT>from third_party_auth.provider import Registry   <EOL><DEDENT>except ImportError as exception:<EOL><INDENT>LOGGER.warning("<STR_LIT>")<EOL>LOGGER.warning(exception)<EOL>Registry = None  <EOL><DEDENT>first = [("<STR_LIT>", "<STR_LIT:->" * <NUM_LIT:7>)]<EOL>if Registry:<EOL><INDENT>return first + [(idp.provider_id, idp.name) for idp in Registry.enabled()]<EOL><DEDENT>return None<EOL>

Get a list of identity providers choices for enterprise customer.

Return:
    A list of choices of all identity providers, None if it can not get any available identity provider.


return [f.name for f in model._meta.get_fields()]<EOL>

Return all fields' names from a model.

According to `Django documentation`_, ``get_all_field_names`` should become some monstrosity with chained
iterable ternary nested in a list comprehension. For now, a simpler version of iterating over fields and
getting their names work, but we might have to switch to full version in future.

.. _Django documentation: https://docs.djangoproject.com/en/1.8/ref/models/meta/


return get_catalog_admin_url_template().format(catalog_id=catalog_id)<EOL>

Get url to catalog details admin page.

Arguments:
    catalog_id (int): Catalog id for which to return catalog details url.

Returns:
     URL pointing to catalog details admin page for the give catalog id.

Example:
    >>> get_catalog_admin_url_template(2)
    "http://localhost:18381/admin/catalogs/catalog/2/change/"


api_base_url = getattr(settings, "<STR_LIT>", "<STR_LIT>")<EOL>match = re.match(r"<STR_LIT>", api_base_url)<EOL>if not match:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>if mode == '<STR_LIT>':<EOL><INDENT>return match.group("<STR_LIT>").rstrip("<STR_LIT:/>") + "<STR_LIT>"<EOL><DEDENT>elif mode == '<STR_LIT>':<EOL><INDENT>return match.group("<STR_LIT>").rstrip("<STR_LIT:/>") + "<STR_LIT>"<EOL><DEDENT>

Get template of catalog admin url.

URL template will contain a placeholder '{catalog_id}' for catalog id.
Arguments:
    mode e.g. change/add.

Returns:
    A string containing template for catalog url.

Example:
    >>> get_catalog_admin_url_template('change')
    "http://localhost:18381/admin/catalogs/catalog/{catalog_id}/change/"


if (<EOL>template_configuration is not None and<EOL>template_configuration.html_template and<EOL>template_configuration.plaintext_template<EOL>):<EOL><INDENT>plain_msg, html_msg = template_configuration.render_all_templates(template_context)<EOL><DEDENT>else:<EOL><INDENT>plain_msg = render_to_string(<EOL>'<STR_LIT>',<EOL>template_context<EOL>)<EOL>html_msg = render_to_string(<EOL>'<STR_LIT>',<EOL>template_context<EOL>)<EOL><DEDENT>return plain_msg, html_msg<EOL>

Create HTML and plaintext message bodies for a notification.

We receive a context with data we can use to render, as well as an optional site
template configration - if we don't get a template configuration, we'll use the
standard, built-in template.

Arguments:
    template_context (dict): A set of data to render
    template_configuration: A database-backed object with templates
        stored that can be used to render a notification.


stock_subject_template = _('<STR_LIT>')<EOL>default_subject_template = getattr(<EOL>settings,<EOL>'<STR_LIT>',<EOL>stock_subject_template,<EOL>)<EOL>if template_configuration is not None and template_configuration.subject_line:<EOL><INDENT>final_subject_template = template_configuration.subject_line<EOL><DEDENT>else:<EOL><INDENT>final_subject_template = default_subject_template<EOL><DEDENT>try:<EOL><INDENT>return final_subject_template.format(course_name=course_name)<EOL><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT>try:<EOL><INDENT>return default_subject_template.format(course_name=course_name)<EOL><DEDENT>except KeyError:<EOL><INDENT>return stock_subject_template.format(course_name=course_name)<EOL><DEDENT>

Get a subject line for a notification email.

The method is designed to fail in a "smart" way; if we can't render a
database-backed subject line template, then we'll fall back to a template
saved in the Django settings; if we can't render _that_ one, then we'll
fall through to a friendly string written into the code.

One example of a failure case in which we want to fall back to a stock template
would be if a site admin entered a subject line string that contained a template
tag that wasn't available, causing a KeyError to be raised.

Arguments:
    course_name (str): Course name to be rendered into the string
    template_configuration: A database-backed object with a stored subject line template


def send_email_notification_message(user, enrolled_in, enterprise_customer, email_connection=None):

if hasattr(user, '<STR_LIT>') and hasattr(user, '<STR_LIT:username>'):<EOL><INDENT>user_name = user.first_name<EOL>if not user_name:<EOL><INDENT>user_name = user.username<EOL><DEDENT><DEDENT>else:<EOL><INDENT>user_name = None<EOL><DEDENT>if hasattr(user, '<STR_LIT:email>'):<EOL><INDENT>user_email = user.email<EOL><DEDENT>elif hasattr(user, '<STR_LIT>'):<EOL><INDENT>user_email = user.user_email<EOL><DEDENT>else:<EOL><INDENT>raise TypeError(_('<STR_LIT>'))<EOL><DEDENT>msg_context = {<EOL>'<STR_LIT>': user_name,<EOL>'<STR_LIT>': enrolled_in,<EOL>'<STR_LIT>': enterprise_customer.name,<EOL>}<EOL>try:<EOL><INDENT>enterprise_template_config = enterprise_customer.enterprise_enrollment_template<EOL><DEDENT>except (ObjectDoesNotExist, AttributeError):<EOL><INDENT>enterprise_template_config = None<EOL><DEDENT>plain_msg, html_msg = build_notification_message(msg_context, enterprise_template_config)<EOL>subject_line = get_notification_subject_line(enrolled_in['<STR_LIT:name>'], enterprise_template_config)<EOL>from_email_address = get_configuration_value_for_site(<EOL>enterprise_customer.site,<EOL>'<STR_LIT>',<EOL>default=settings.DEFAULT_FROM_EMAIL<EOL>)<EOL>return mail.send_mail(<EOL>subject_line,<EOL>plain_msg,<EOL>from_email_address,<EOL>[user_email],<EOL>html_message=html_msg,<EOL>connection=email_connection<EOL>)<EOL>

Send an email notifying a user about their enrollment in a course.

Arguments:
    user: Either a User object or a PendingEnterpriseCustomerUser that we can use
        to get details for the email
    enrolled_in (dict): The dictionary contains details of the enrollable object
        (either course or program) that the user enrolled in. This MUST contain
        a `name` key, and MAY contain the other following keys:
            - url: A human-friendly link to the enrollable's home page
            - type: Either `course` or `program` at present
            - branding: A special name for what the enrollable "is"; for example,
                "MicroMasters" would be the branding for a "MicroMasters Program"
            - start: A datetime object indicating when the enrollable will be available.
    enterprise_customer: The EnterpriseCustomer that the enrollment was created using.
    email_connection: An existing Django email connection that can be used without
        creating a new connection for each individual message


EnterpriseCustomer = apps.get_model('<STR_LIT>', '<STR_LIT>')  <EOL>try:<EOL><INDENT>return EnterpriseCustomer.objects.get(uuid=uuid)  <EOL><DEDENT>except EnterpriseCustomer.DoesNotExist:<EOL><INDENT>return None<EOL><DEDENT>

Get the ``EnterpriseCustomer`` instance associated with ``uuid``.

:param uuid: The universally unique ID of the enterprise customer.
:return: The ``EnterpriseCustomer`` instance, or ``None`` if it doesn't exist.


EnterpriseCustomerUser = apps.get_model('<STR_LIT>', '<STR_LIT>')  <EOL>try:<EOL><INDENT>return EnterpriseCustomerUser.objects.get(user_id=auth_user.id).enterprise_customer  <EOL><DEDENT>except EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>return None<EOL><DEDENT>

Return enterprise customer instance for given user.

Some users are associated with an enterprise customer via `EnterpriseCustomerUser` model,
    1. if given user is associated with any enterprise customer, return enterprise customer.
    2. otherwise return `None`.

Arguments:
    auth_user (contrib.auth.User): Django User

Returns:
    (EnterpriseCustomer): enterprise customer associated with the current user.


EnterpriseCustomerUser = apps.get_model('<STR_LIT>', '<STR_LIT>')  <EOL>try:<EOL><INDENT>return EnterpriseCustomerUser.objects.get(  <EOL>enterprise_customer__uuid=enterprise_uuid,<EOL>user_id=user_id<EOL>)<EOL><DEDENT>except EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>return None<EOL><DEDENT>

Return the object for EnterpriseCustomerUser.

Arguments:
    user_id (str): user identifier
    enterprise_uuid (UUID): Universally unique identifier for the enterprise customer.

Returns:
    (EnterpriseCustomerUser): enterprise customer user record


try:<EOL><INDENT>course_root = reverse('<STR_LIT>', kwargs={'<STR_LIT>': course_run['<STR_LIT:key>']})<EOL><DEDENT>except KeyError:<EOL><INDENT>LOGGER.exception(<EOL>"<STR_LIT>", course_run,<EOL>)<EOL>raise<EOL><DEDENT>url = '<STR_LIT>'.format(<EOL>settings.LMS_ROOT_URL,<EOL>course_root<EOL>)<EOL>course_run_url = update_query_parameters(url, query_parameters)<EOL>return course_run_url<EOL>

Return track selection url for the given course.

Arguments:
    course_run (dict): A dictionary containing course run metadata.
    query_parameters (dict): A dictionary containing query parameters to be added to course selection url.

Raises:
    (KeyError): Raised when course run dict does not have 'key' key.

Returns:
    (str): Course track selection url.


scheme, netloc, path, query_string, fragment = urlsplit(url)<EOL>url_params = parse_qs(query_string)<EOL>url_params.update(query_parameters)<EOL>return urlunsplit(<EOL>(scheme, netloc, path, urlencode(sorted(url_params.items()), doseq=True), fragment),<EOL>)<EOL>

Return url with updated query parameters.

Arguments:
    url (str): Original url whose query parameters need to be updated.
    query_parameters (dict): A dictionary containing query parameters to be added to course selection url.

Returns:
    (slug): slug identifier for the identity provider that can be used for identity verification of
        users associated the enterprise customer of the given user.


audit_modes = getattr(settings, '<STR_LIT>', ['<STR_LIT>'])<EOL>if not enterprise_customer.enable_audit_enrollment:<EOL><INDENT>return [course_mode for course_mode in course_modes if course_mode['<STR_LIT>'] not in audit_modes]<EOL><DEDENT>return course_modes<EOL>

Filter audit course modes out if the enterprise customer has not enabled the 'Enable audit enrollment' flag.

Arguments:
    enterprise_customer: The EnterpriseCustomer that the enrollment was created using.
    course_modes: iterable with dictionaries containing a required 'mode' key


EnterpriseCustomer = apps.get_model('<STR_LIT>', '<STR_LIT>')  <EOL>try:<EOL><INDENT>enterprise_uuid = UUID(enterprise_uuid)<EOL>return EnterpriseCustomer.objects.get(uuid=enterprise_uuid)  <EOL><DEDENT>except (TypeError, ValueError, EnterpriseCustomer.DoesNotExist):<EOL><INDENT>LOGGER.error('<STR_LIT>', enterprise_uuid)<EOL>raise Http404<EOL><DEDENT>

Given an EnterpriseCustomer UUID, return the corresponding EnterpriseCustomer or raise a 404.

Arguments:
    enterprise_uuid (str): The UUID (in string form) of the EnterpriseCustomer to fetch.

Returns:
    (EnterpriseCustomer): The EnterpriseCustomer given the UUID.


<EOL>return text.replace('<STR_LIT>', '<STR_LIT>')<EOL>

Given html text that will be rendered as a variable in a template, strip out characters that impact rendering.

Arguments:
    text (str): The text to clean.

Returns:
    (str): The cleaned text.


key = '<STR_LIT>'.join(['<STR_LIT>'.format(item, value) for item, value in iteritems(kwargs)])<EOL>return hashlib.md5(key.encode('<STR_LIT:utf-8>')).hexdigest()<EOL>

Get MD5 encoded cache key for given arguments.

Here is the format of key before MD5 encryption.
    key1:value1__key2:value2 ...

Example:
    >>> get_cache_key(site_domain="example.com", resource="enterprise")
    # Here is key format for above call
    # "site_domain:example.com__resource:enterprise"
    a54349175618ff1659dee0978e3149ca

Arguments:
    **kwargs: Key word arguments that need to be present in cache key.

Returns:
     An MD5 encoded key uniquely identified by the key word arguments.


results = response.get('<STR_LIT>', [])<EOL>next_page = response.get('<STR_LIT>')<EOL>while next_page:<EOL><INDENT>querystring = parse_qs(urlparse(next_page).query, keep_blank_values=True)<EOL>response = endpoint.get(**querystring)<EOL>results += response.get('<STR_LIT>', [])<EOL>next_page = response.get('<STR_LIT>')<EOL><DEDENT>return results<EOL>

Traverse a paginated API response.

Extracts and concatenates "results" (list of dict) returned by DRF-powered
APIs.

Arguments:
    response (Dict): Current response dict from service API
    endpoint (slumber Resource object): slumber Resource object from edx-rest-api-client

Returns:
    list of dict.