def send_onboarding_email(enterprise_customer_uuid, user_email): """ Sends onboarding email to learner. Intended for use following license activation. Arguments: enterprise_customer_uuid (UUID): unique identifier of the EnterpriseCustomer that is linked to the SubscriptionPlan associated with the activated license user_email (str): email of the learner whose license has just been activated """ enterprise_customer = EnterpriseApiClient().get_enterprise_customer_data( enterprise_customer_uuid) enterprise_name = enterprise_customer.get('name') enterprise_slug = enterprise_customer.get('slug') enterprise_sender_alias = get_enterprise_sender_alias(enterprise_customer) context = { 'subject': ONBOARDING_EMAIL_SUBJECT, 'template_name': ONBOARDING_EMAIL_TEMPLATE, 'ENTERPRISE_NAME': enterprise_name, 'ENTERPRISE_SLUG': enterprise_slug, 'HELP_CENTER_URL': settings.SUPPORT_SITE_URL, 'LEARNER_PORTAL_LINK': get_learner_portal_url(enterprise_slug), 'MOBILE_STORE_URLS': settings.MOBILE_STORE_URLS, 'RECIPIENT_EMAIL': user_email, 'SOCIAL_MEDIA_FOOTER_URLS': settings.SOCIAL_MEDIA_FOOTER_URLS, } email = _message_from_context_and_template(context, enterprise_sender_alias) email.send()
def _validate_enterprise_customer_uuid(self): """ Verifies that a customer with the given enterprise_customer_uuid exists """ enterprise_customer_uuid = self.instance.enterprise_customer_uuid try: customer_data = EnterpriseApiClient().get_enterprise_customer_data( enterprise_customer_uuid) self.instance.enterprise_customer_slug = customer_data.get('slug') self.instance.enterprise_customer_name = customer_data.get('name') return True except HTTPError as ex: logger.exception( f'Could not validate enterprise_customer_uuid {enterprise_customer_uuid}.' ) if ex.response.status_code == status.HTTP_404_NOT_FOUND: self.add_error( 'enterprise_customer_uuid', f'An enterprise customer with uuid: {enterprise_customer_uuid} does not exist.', ) else: self.add_error( 'enterprise_customer_uuid', f'Could not verify the given UUID: {ex}. Please try again.', ) return False
def send_post_activation_email_task(enterprise_customer_uuid, user_email): """ Asynchronously sends post license activation email to learner. """ enterprise_customer = EnterpriseApiClient().get_enterprise_customer_data( enterprise_customer_uuid) enterprise_name = enterprise_customer.get('name') enterprise_slug = enterprise_customer.get('slug') enterprise_sender_alias = get_enterprise_sender_alias(enterprise_customer) enterprise_contact_email = enterprise_customer.get('contact_email') braze_campaign_id = settings.BRAZE_ACTIVATION_EMAIL_CAMPAIGN braze_trigger_properties = { 'enterprise_customer_slug': enterprise_slug, 'enterprise_customer_name': enterprise_name, 'enterprise_sender_alias': enterprise_sender_alias, 'enterprise_contact_email': enterprise_contact_email, } recipient = _aliased_recipient_object_from_email(user_email) try: braze_client_instance = BrazeApiClient() braze_client_instance.create_braze_alias( [user_email], ENTERPRISE_BRAZE_ALIAS_LABEL, ) braze_client_instance.send_campaign_message( braze_campaign_id, recipients=[recipient], trigger_properties=braze_trigger_properties, ) except BrazeClientError as exc: message = ('Error hitting Braze API. ' f'Onboarding email to {user_email} for license failed.') logger.exception(message) raise exc
def sync_agreement_with_enterprise_customer(customer_agreement): """ Syncs any updates made to the enterprise customer slug or name as returned by the ``EnterpriseApiClient`` with the specified ``CustomerAgreement``. """ try: customer_data = EnterpriseApiClient().get_enterprise_customer_data( customer_agreement.enterprise_customer_uuid, ) customer_agreement.enterprise_customer_slug = customer_data.get('slug') customer_agreement.enterprise_customer_name = customer_data.get('name') customer_agreement.save() except HTTPError as exc: error_message = ( 'Could not fetch customer fields from the enterprise API: {}'.format(exc) ) raise CustomerAgreementError(error_message) from exc
def enterprise_enrollment_license_subsidy_task( bulk_enrollment_job_uuid, enterprise_customer_uuid, learner_emails, course_run_keys, notify_learners, subscription_uuid, ): """ Enroll a list of enterprise learners into a list of course runs with or without notifying them. Optionally, filter license check by a specific subscription. Arguments: bulk_enrollment_job_uuid (str): UUID (string representation) for a BulkEnrollmentJob created by the enqueuing process for logging and progress tracking table updates. enterprise_customer_uuid (str): UUID (string representation) the enterprise customer id learner_emails (list(str)): email addresses of the learners to enroll course_run_keys (list(str)): course keys of the courses to enroll the learners into notify_learners (bool): whether or not to send notifications of their enrollment to the learners subscription_uuid (str): UUID (string representation) of the specific enterprise subscription to use when validating learner licenses """ # AED 2022-01-24 - I don't have enough context to unwind this sanely. # Declaring bankruptcy for now. # pylint: disable=too-many-nested-blocks try: logger.info('starting enterprise_enrollment_license_subsidy_task for ' f'bulk_enrollment_job_uuid={bulk_enrollment_job_uuid} ' f'enterprise_customer_uuid={enterprise_customer_uuid}') # collect/return results (rather than just write to the CSV) to help testability results = [] bulk_enrollment_job = BulkEnrollmentJob.objects.get( uuid=bulk_enrollment_job_uuid) customer_agreement = CustomerAgreement.objects.get( enterprise_customer_uuid=enterprise_customer_uuid) # this is to avoid hitting timeouts on the enterprise enroll api # take course keys 25 at a time, for each course key chunk, take learners 25 at a time for course_run_key_batch in chunks(course_run_keys, 25): logger.debug( "enterprise_customer_uuid={} course_run_key_batch size: {}". format(enterprise_customer_uuid, len(course_run_key_batch))) for learner_enrollment_batch in chunks(learner_emails, 25): logger.debug( "enterprise_customer_uuid={} learner_enrollment_batch size: {}" .format(enterprise_customer_uuid, len(learner_enrollment_batch))) missing_subscriptions, licensed_enrollment_info = utils.check_missing_licenses( customer_agreement, learner_enrollment_batch, course_run_key_batch, subscription_uuid=subscription_uuid, ) if missing_subscriptions: for failed_email, course_keys in missing_subscriptions.items( ): for course_key in course_keys: results.append([ failed_email, course_key, 'failed', 'missing subscription' ]) if licensed_enrollment_info: options = { 'licenses_info': licensed_enrollment_info, 'notify': notify_learners } enrollment_result = EnterpriseApiClient( ).bulk_enroll_enterprise_learners( str(enterprise_customer_uuid), options).json() for success in enrollment_result['successes']: results.append([ success.get('email'), success.get('course_run_key'), 'success', '' ]) for pending in enrollment_result['pending']: results.append([ pending.get('email'), pending.get('course_run_key'), 'pending', 'pending license activation' ]) for failure in enrollment_result['failures']: results.append([ failure.get('email'), failure.get('course_run_key'), 'failed', '' ]) if enrollment_result.get('invalid_email_addresses'): for result_email in enrollment_result[ 'invalid_email_addresses']: for course_key in course_run_key_batch: results.append([ result_email, course_key, 'failed', 'invalid email address' ]) with NamedTemporaryFile(mode='w', delete=False) as result_file: result_writer = csv.writer(result_file) result_writer.writerow( ['email address', 'course key', 'enrollment status', 'notes']) for result in results: result_writer.writerow(result) result_file.close() if hasattr(settings, "BULK_ENROLL_JOB_AWS_BUCKET" ) and settings.BULK_ENROLL_JOB_AWS_BUCKET: bulk_enrollment_job.upload_results(result_file.name) if hasattr(settings, "BULK_ENROLL_RESULT_CAMPAIGN" ) and settings.BULK_ENROLL_RESULT_CAMPAIGN: _send_bulk_enrollment_results_email( bulk_enrollment_job=bulk_enrollment_job, campaign_id=settings.BULK_ENROLL_RESULT_CAMPAIGN, ) return results except Exception as ex: msg = ('failed enterprise_enrollment_license_subsidy_task for ' f'bulk_enrollment_job_uuid={bulk_enrollment_job_uuid} ' f'enterprise_customer_uuid={enterprise_customer_uuid}') logger.error(msg, exc_info=True) raise ex