def post(self, request, **kwargs): body_unicode = request.body.decode("utf-8") body = json.loads(body_unicode) username = body["username"] pathway_id = body["pathway_id"] program_uuid = kwargs["uuid"] # verify that the user or an admin is making the request if username != request.user.get_username() and not request.user.is_staff: return JsonResponse({"error": "Permission denied"}, status=403) credential = UserCredential.objects.filter( username=username, status=UserCredential.AWARDED, program_credentials__program_uuid=program_uuid ) program = get_object_or_404(Program, uuid=program_uuid, site=request.site) pathway = get_object_or_404( Pathway, id=pathway_id, programs__uuid=program_uuid, pathway_type=PathwayType.CREDIT.value, ) certificate = get_object_or_404(ProgramCertificate, program_uuid=program_uuid, site=request.site) user = get_object_or_404(User, username=username) public_record, _ = ProgramCertRecord.objects.get_or_create(user=user, program=program) # Make sure we haven't already sent an email with a 'sent' status if UserCreditPathway.objects.filter(user=user, pathway=pathway, status=UserCreditPathwayStatus.SENT).exists(): return JsonResponse({"error": "Pathway email already sent"}, status=400) record_path = reverse("records:public_programs", kwargs={"uuid": public_record.uuid.hex}) record_link = request.build_absolute_uri(record_path) csv_link = urllib.parse.urljoin(record_link, "csv") msg = ProgramCreditRequest(request.site, user.email).personalize( recipient=Recipient(username=None, email_address=pathway.email), language=certificate.language, user_context={ "pathway_name": pathway.name, "program_name": program.title, "record_link": record_link, "user_full_name": request.user.get_full_name() or request.user.username, "program_completed": credential.exists(), "previously_sent": False, "csv_link": csv_link, }, ) ace.send(msg) # Create a record of this email so that we can't send multiple times # If the status was previously changed, we want to reset it to SENT UserCreditPathway.objects.update_or_create( user=user, pathway=pathway, defaults={"status": UserCreditPathwayStatus.SENT}, ) return http.HttpResponse(status=200)
def send_program_certificate_created_message(username, program_certificate): """ If the learner has earned a Program Certificate then we go ahead and send them an automated email congratulating them for their achievement. Emails to learners in credit eligible Programs will contain additional information. """ user = User.objects.get(username=username) program_uuid = program_certificate.program_uuid program_details = program_certificate.program_details email_configuration = ProgramCompletionEmailConfiguration.get_email_config_for_program( program_uuid, program_details.type_slug) # If a config doesn't exist or isn't enabled, we don't want to send emails for this program. if not getattr(email_configuration, "enabled", None): log.info( f"Not sending program completion email to learner [{user.id}] " f"in program [{program_uuid}] because it's not enabled") return # Don't send out emails for retired programs if program_details.status == ProgramStatus.RETIRED.value: return try: msg = ProgramCertificateIssuedMessage( program_certificate.site, user.email ).personalize( recipient=Recipient(username=user.username, email_address=user.email), language=program_certificate.language, user_context={ "program_title": program_details.title, "program_type": program_details.type, "custom_email_html_template_extra": email_configuration.html_template, # remove any leading spaces of the plaintext content so that the email doesn't look horrendous "custom_email_plaintext_template_extra": textwrap.dedent(email_configuration.plaintext_template), "logo_url": getattr(settings, "LOGO_URL_PNG", ""), }, ) log.info( f"Sending Program completion email to learner with id [{user.id}] in Program [{program_uuid}]" ) ace.send(msg) # We wouldn't want any issues that arise from formatting or sending this email message to interrupt the process # of issuing a learner their Program Certificate. We cast a wide net for exceptions here for this reason. except Exception as ex: # pylint: disable=broad-except log.exception( f"Unable to send email to learner with id: [{user.id}] for Program [{program_uuid}]. " f"Error occurred while attempting to format or send message: {ex}")
def send_updated_emails_for_program(username, program_certificate): """ If the user has previously sent an email to a pathway org, we want to send an updated one when they finish the program. This function is called from the credentials Program Certificate awarding API """ site = program_certificate.site user = User.objects.get(username=username) program_uuid = program_certificate.program_uuid program = Program.objects.prefetch_related('pathways').get( site=site, uuid=program_uuid) pathways_set = frozenset(program.pathways.all()) user_pathways = UserCreditPathway.objects.select_related('pathway').filter( user=user, pathway__in=pathways_set, status=UserCreditPathwayStatus.SENT) # Return here if the user doesn't have a program cert record try: pcr = ProgramCertRecord.objects.get(program=program, user=user) except ProgramCertRecord.DoesNotExist: logger.exception( "Program Cert Record for user_uuid %s, program_uuid %s does not exist", user.id, program.uuid) return # Send emails for those already marked as "SENT" for user_pathway in user_pathways: pathway = user_pathway.pathway record_path = reverse('records:public_programs', kwargs={'uuid': pcr.uuid.hex}) record_link = site.domain + record_path csv_link = urllib.parse.urljoin(record_link, "csv") msg = ProgramCreditRequest(site).personalize( recipient=Recipient(username=None, email_address=pathway.email), language=program_certificate.language, user_context={ 'pathway_name': pathway.name, 'program_name': program.title, 'record_link': record_link, 'user_full_name': user.get_full_name(), 'program_completed': True, 'previously_sent': True, 'csv_link': csv_link, }, ) ace.send(msg)
def send_program_certificate_created_message(username, program_certificate): """ If the learner has earned a Program Certificate then we go ahead and send them an automated email congratulating them for their achievement. Emails to learners in credit eligible Programs will contain additional information. """ user = User.objects.get(username=username) program_uuid = program_certificate.program_uuid program = Program.objects.get(site=program_certificate.site, uuid=program_uuid) custom_completion_email_settings = getattr( settings, 'CUSTOM_COMPLETION_EMAIL_TEMPLATE_EXTRA', {}) custom_completion_email_content = ( custom_completion_email_settings.get(str(program_uuid), {}) or custom_completion_email_settings.get(program.type_slug, {}) or {}) try: msg = ProgramCertificateIssuedMessage( program_certificate.site, user.email ).personalize( recipient=Recipient(username=user.username, email_address=user.email), language=program_certificate.language, user_context={ 'program_title': program.title, 'program_type': program.type, 'custom_email_html_template_extra': custom_completion_email_content.get('html', ''), # remove any leading spaces of the plaintext content so that the email doesn't look horrendous 'custom_email_plaintext_template_extra': textwrap.dedent( custom_completion_email_content.get('plaintext', '')), }, ) log.info( "Sending Program completion email to learner with id [{}] in Program [{}]" .format(user.id, program_uuid)) ace.send(msg) # We wouldn't want any issues that arise from formatting or sending this email message to interrupt the process # of issuing a learner their Program Certificate. We cast a wide net for exceptions here for this reason. except Exception as ex: # pylint: disable=broad-except log.exception( "Unable to send email to learner with id: [{}] for Program [{}]. Error occurred while " "attempting to format or send message: {}".format( user.id, program_uuid, ex))
def setUp(self): patcher = patch( 'openedx.core.djangoapps.schedules.templatetags.ace.get_current_request' ) self.mock_get_current_request = patcher.start() self.addCleanup(patcher.stop) self.fake_request = HttpRequest() self.fake_request.user = UserFactory.create() self.fake_request.site = SiteFactory.create() self.fake_request.site.domain = 'example.com' self.mock_get_current_request.return_value = self.fake_request self.message = Message( app_label='test_app_label', name='test_name', recipient=Recipient(username='******'), context={}, send_uuid=uuid.uuid4(), ) self.context = {'message': self.message}
def setUp(self): super(EmailTemplateTagMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments patcher = patch( 'openedx.core.djangoapps.ace_common.templatetags.ace.get_current_request' ) self.mock_get_current_request = patcher.start() self.addCleanup(patcher.stop) self.fake_request = HttpRequest() self.fake_request.user = UserFactory.create() self.fake_request.site = SiteFactory.create() self.fake_request.site.domain = 'example.com' self.mock_get_current_request.return_value = self.fake_request self.message = Message( app_label='test_app_label', name='test_name', recipient=Recipient(username='******'), context={}, send_uuid=uuid.uuid4(), ) self.context = {'message': self.message}