def send_email_change_verification(self, request): """Send a verification email to the new email address""" user = self.user context = { "user": user, "validation_link": request.build_absolute_uri( reverse( "user:validate_email_change", kwargs={ "uidb64": urlsafe_base64_encode(force_bytes(user.id)), "token": account_activation_token.make_token(user), }, )), } subject = render_to_string( "userdb/email/user_email_change_verification_subject.txt", context) text_content = render_to_string( "userdb/email/user_email_change_verification_email.txt", context) html_content = render_to_string( "userdb/email/user_email_change_verification_email.html", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.new_email_pending_verification], html_message=html_content, fail_silently=False, )
def send_validation_link(self): user = self.user context = { "user": user, "validation_link": reverse( "user:validate_email", kwargs={ "uidb64": urlsafe_base64_encode(force_bytes(user.id)), "token": account_activation_token.make_token(user), }, ), } subject = render_to_string( "userdb/email/user_verification_subject.txt", context) text_content = render_to_string( "userdb/email/user_verification_email.txt", context) html_content = render_to_string( "userdb/email/user_verification_email.html", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.user.email], html_message=html_content, fail_silently=False, )
def send_email_renewal_reminder(self): """Send an email renewal reminder""" user = self.assigned_teammember.user context = { "user": user, "server_name": self.server_name, "renewal_url": settings.DEFAULT_DOMAIN + self.renewal_url, "expiry": self.expiry, "days_remaining": self.time_remaining.days, "hours_remaining": self.time_remaining.days * 24 + self.time_remaining.seconds // 3600, } subject = render_to_string( "openstack/email/server_lease_expiry_reminder_subject.txt", context) text_content = render_to_string( "openstack/email/server_lease_expiry_reminder_email.txt", context) html_content = render_to_string( "openstack/email/server_lease_expiry_reminder_email.html", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [user.email], html_message=html_content, fail_silently=False, ) self.last_reminder_sent_at = timezone.now() self.save()
def test_task_with_default_audit_type(self, sync_send): sync_send.return_value = notify_response audit_kwargs = self.audit_kwargs.copy() del audit_kwargs["audit_type"] send_mail(self.email, self.context, self.template_id, audit_kwargs=audit_kwargs) audit = Audit.objects.first() self.assertEqual(audit.type, AUDIT_TYPE_NOTIFY)
def test_task_with_retryable_error(self, sync_send, retry): error = create_error_response(message="ServerError", status_code=500) sync_send.side_effect = error send_mail(self.email, self.context, self.template_id, audit_kwargs=self.audit_kwargs) retry.assert_called_once_with( countdown=SEND_MAIL_COUNTDOWN, max_retries=SEND_MAIL_MAX_RETRIES, exc=error ) self.assertEqual(sync_send.call_count, 1) self.assertEqual(Audit.objects.all().count(), 1)
def send_team_licence_reminder_emails(self): """ Send team licence expiry reminder emails to primary and secondary users """ context = { "team": self, "team_management_url": f"{settings.DEFAULT_DOMAIN}/teams/{self.hashid}/team", "time_remaining": (self.licence_expiry - timezone.now()), "termination_date": self.licence_expiry + datetime.timedelta(days=settings.LICENCE_TERMINATION_DAYS), "licence_terms_url": settings.DEFAULT_DOMAIN + reverse("user:licence"), "licence_email_signatories": settings.LICENCE_EMAIL_SIGNATORIES, } # Email each team member for user in self.users.all(): context["user"] = user subject = render_to_string( "userdb/email/team_licence_reminder_subject.txt", context) if user in self.admin_users.all(): text_content = render_to_string( "userdb/email/team_licence_reminder_primary_user_email.txt", context) html_content = render_to_string( "userdb/email/team_licence_reminder_primary_user_email.html", context, ) else: text_content = render_to_string( "userdb/email/team_licence_reminder_secondary_user_email.txt", context, ) html_content = render_to_string( "userdb/email/team_licence_reminder_secondary_user_email.html", context, ) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [user.email], html_message=html_content, fail_silently=True, ) # Update team self.licence_last_reminder_sent_at = timezone.now() self.save()
def test_task(self, sync_send): sync_send.return_value = notify_response send_mail(self.email, self.context, self.template_id, audit_kwargs=self.audit_kwargs) sync_send.assert_called_once_with( self.email, self.context, self.template_id, self.reference ) self.assertEqual(Audit.objects.all().count(), 1) audit = Audit.objects.first() self.assertEqual(audit.type, AUDIT_TYPE_EVENT) self.assertEqual(audit.created_by, self.user) self.assertEqual(audit.data["k-1"], "v-1") self.assertEqual(audit.data["send_report"], notify_response)
def send_lease_granted_email(self): context = {"server_lease_request": self} subject = render_to_string( "openstack/email/server_lease_request_granted_subject.txt", context, ).strip() html_content = render_to_string( "openstack/email/server_lease_request_granted_email.html", context) text_content = main_text_from_html(html_content) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.user.email], html_message=html_content, fail_silently=False, )
def notify_owners(self, organisation, template_id, context, notified_by): audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "user": notified_by, } owners = organisation.organisationuser_set.filter( user__is_active=True, user__groups__name="Organisation Owner") for owner in owners: user = owner.user context["full_name"] = user.name context["organisation_name"] = organisation.name audit_kwargs["model"] = user.contact context["login_url"] = public_login_url() send_mail(user.contact.email, context, template_id, audit_kwargs=audit_kwargs)
def send_invitation_email(self): context = { "invitation": self, "url": reverse("user:accept_invitation", args=[self.uuid]), } subject = render_to_string("userdb/email/user_invite_subject.txt", context).strip() html_content = render_to_string("userdb/email/user_invite_email.html", context) text_content = main_text_from_html(html_content) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.email], html_message=html_content, fail_silently=False, )
def send_email_change_notification(self, request): """Send an email change notification to the existing/previous email address""" user = self.user context = { "user": user, } subject = render_to_string( "userdb/email/user_email_change_notification_subject.txt", context) text_content = render_to_string( "userdb/email/user_email_change_notification_email.txt", context) html_content = render_to_string( "userdb/email/user_email_change_notification_email.html", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.user.email], html_message=html_content, fail_silently=False, )
def send_admin_notification_email(self): admin_emails = settings.REGION_ADMINS.get( self.server_lease.tenant.region.name) if not admin_emails: return context = {"server_lease_request": self} subject = render_to_string( "openstack/email/server_lease_request_admin_notification_subject.txt", context, ).strip() text_content = render_to_string( "openstack/email/server_lease_request_admin_notification_email.txt", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, admin_emails, fail_silently=False, )
def post(self, request): email = request.data.get("email") try: user = User.objects.get(email=email) if user: ascii_letters = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' activation_key = ''.join(random.choice(ascii_letters) for i in range(16)) print activation_key user_profile, create = UserProfile.objects.get_or_create(user=user) user_profile.token = activation_key user_profile.save() data = {'user': user, 'activation_key': activation_key} email_template = render_to_string("send_email.html", data) send_mail("Login Authentication", email_template, user.email, [user.email]) return JsonResponse({ 'success': True, 'login_page': reverse('dashboard:sign-in', request=request) }) except User.DoesNotExist: return JsonResponse({ 'error': True })
def verify_and_send_notification_email(self): """ Admin script: mark team as verified and notify the primary user """ context = {"user": self.owner, "team": self} subject = render_to_string( "userdb/email/notify_team_verified_subject.txt", context).strip() html_content = render_to_string( "userdb/email/notify_team_verified_email.html", context) text_content = main_text_from_html(html_content) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, [self.owner.email], html_message=html_content, fail_silently=False, ) self.verified = True self.save()
def send_new_team_admin_email(self): """ Notify admin(s) of new team registration """ if not settings.NEW_REGISTRATION_ADMIN_EMAILS: return context = {"user": self.creator, "team": self} subject = render_to_string( "userdb/email/new_registration_admin_subject.txt", context) text_content = render_to_string( "userdb/email/new_registration_admin_email.txt", context) html_content = render_to_string( "userdb/email/new_registration_admin_email.html", context) send_mail( subject, text_content, settings.DEFAULT_FROM_EMAIL, settings.NEW_REGISTRATION_ADMIN_EMAILS, html_message=html_content, fail_silently=True, )
def test_task_with_non_retryable_error(self, sync_send): sync_send.side_effect = create_error_response(message="BadRequest") send_mail(self.email, self.context, self.template_id, audit_kwargs=self.audit_kwargs) sync_send.assert_called_once_with( self.email, self.context, self.template_id, self.reference ) self.assertEqual(Audit.objects.all().count(), 1) audit = Audit.objects.first() self.assertEqual(audit.type, AUDIT_TYPE_EVENT) self.assertEqual(audit.created_by, self.user) self.assertEqual( audit.data, { "case_title": str(self.case), "k-1": "v-1", "send_report": { "email": self.email, "error": ["BadRequest"], "template_id": self.template_id, "values": {"a": "b"}, }, }, )
def perform_create(self, serializer): send_mail(serializer.validated_data['email'], serializer.validated_data['username']) serializer.save()
def notify_deficiency(self, sent_by, contact=None, context=None, template_id=None): """ Notify the contact about a deficiency to this submission using the given template. If no template is provided, the type's default is used falling back to the default deficiency template. """ contact = contact or self.contact template_id = "NOTIFY_SUBMISSION_DEFICIENCY" if context.get("submission_type", "") == "Application": template_id = "NOTIFY_APPLICATION_INSUFFICIENT_V2" notify_template_id = SystemParameter.get(template_id) product = self.case.product_set.first() product_name = product.name if product else "" case_name = self.case.name company_name = titlecase(self.organisation.name) # set the due date on this submission self.set_due_date(force=True) values = { "company": company_name, "investigation_type": self.case.type.name, "product": product_name, "full_name": contact.name.strip() if contact else "N/A", "organisation_name": company_name, "case_number": self.case.reference, "case_name": case_name, "tra_contact_name": "us", "submission_type": self.type.name, "login_url": public_login_url(), "deadline": self.due_at.strftime(settings.FRIENDLY_DATE_FORMAT) if self.due_at else "N/A", } if context: values.update(context) audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "user": sent_by, "case": self.case, "model": contact, } send_mail(contact.email, values, notify_template_id, audit_kwargs=audit_kwargs) self.deficiency_sent_at = timezone.now() self.sent_at = timezone.now() self.save()
def notify(self, sent_by, contact=None, context=None, template_id=None, new_status=None): """ Notify the contact about this submission using the given template :param core.User sent_by: The user performing an action on the submission. :param contacts.Contact contact: An optional contact to be notified. Defaults to the submission's designated contact. :param dict context: An optional dictionary of parameters to be made available to the template. :param str template_id: An optional string representing the key of a Notify template in the System Parameters. Defaults to NOTIFY_QUESTIONNAIRE :param str new_status: An optional status that the submission will be moved to after sending the notification. This value should correspond to the property of the SubmissionType excluding the `_status` suffix eg: - `sent` -> self.type.sent_status - `received` -> self.type.received_status Defaults to None ie the submission status will not change. """ contact = contact or self.contact template_id = template_id or "NOTIFY_QUESTIONNAIRE" if template_id == "NOTIFY_APPLICATION_SUCCESSFUL": template_id = "NOTIFY_APPLICATION_SUCCESSFUL_V2" notify_template_id = SystemParameter.get(template_id) export_sources = self.case.exportsource_set.filter( deleted_at__isnull=True) export_countries = [src.country.name for src in export_sources] product = self.case.product_set.first() case_name = self.case.name company_name = titlecase(self.organisation.name) values = { "company": self.organisation.name, "investigation_type": self.case.type.name, "product": product.name if product else "", "case_name": case_name, "case_number": self.case.reference, "full_name": contact.name.strip() if contact else "N/A", "country": ", ".join(export_countries) if export_countries else "N/A", "organisation_name": company_name, "company_name": company_name, "login_url": public_login_url(), "submission_type": self.type.name, "deadline": self.due_at.strftime(settings.FRIENDLY_DATE_FORMAT) if self.due_at else "", "dumped_or_subsidised": self.case.dumped_or_subsidised(), "case_title": case_name, # TODO: merge the two identicals "notice_url": self.case.latest_notice_of_initiation_url, # TODO: remove "notice_of_initiation_url": self.case.latest_notice_of_initiation_url, } if context: if template_id == "NOTIFY_QUESTIONNAIRE": context[ "footer"] = "Investigations Team\r\nTrade Remedies\r\nDepartment for International Trade" # /PS-IGNORE values.update(context) if template_id == "NOTIFY_AD_HOC_EMAIL": values[ "footer"] = "Investigations Team\r\nTrade Remedies\r\nDepartment for International Trade\r\nContact: [email protected]" # /PS-IGNORE audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "user": sent_by, "case": self.case, "model": contact, } send_mail(contact.email, values, notify_template_id, audit_kwargs=audit_kwargs) if new_status: self.status = getattr(self.type, f"{new_status}_status") if new_status == "sent": self.sent_at = timezone.now() self.set_due_date() self.save()
"approve": "NOTIFY_INTERESTED_PARTY_REQUEST_PERMITTED", "deny": "NOTIFY_INTERESTED_PARTY_REQUEST_DENIED", "change": "NOTIFY_COMPANY_ROLE_CHANGED_V2", "remove": "NOTIFY_COMPANY_ROLE_DENIED_V2", } template_id = templates_map.get(action) if template_id: notify_template_id = SystemParameter.get(template_id) audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "user": sent_by, "case": case, "model": contact, } send_mail(contact.email, values, notify_template_id, audit_kwargs=audit_kwargs) else: logger.error("Invalid action for organisation notification: %s", action) def has_previous_names(self): """ Returns True if this organisation has had a name change in the past """ return self.organisationname_set.exists() @property def case_count(self): return len(OrganisationCaseRole.objects.case_prepared(self.id))
class AssignUserToCaseView(TradeRemediesApiView): def get(self, request, organisation_id, user_id=None): from cases.models import Submission organisation = Organisation.objects.get(id=organisation_id) if user_id: user = User.objects.get(id=user_id) contact_ids = [user.contact.id] else: users = organisation.users contact_ids = users.values_list("user__userprofile__contact", flat=True) submissions = Submission.objects.filter( (Q(status__draft=True) | Q(status__received=True)), contact_id__in=contact_ids, created_by__in=users.values_list("user", flat=True), type__key="assign", ) return ResponseSuccess( {"results": [submission.to_dict() for submission in submissions]}) @transaction.atomic def post( self, request, organisation_id, user_id, case_id, representing_id=None, submission_id=None, invite_id=None, ): from cases.models import get_case primary = request.data.get("primary") remove = request.data.get("remove") try: user_organisation = Organisation.objects.get(id=organisation_id) if representing_id: representing = Organisation.objects.get(id=representing_id) else: representing = user_organisation except Organisation.DoesNotExist: raise NotFoundApiExceptions("Invalid parameters or access denied") if not request.user.is_tra() and user_id and (user_id != request.user.id): if not request.user.groups.filter( name=SECURITY_GROUP_ORGANISATION_OWNER).exists(): raise InvalidAccess( "Only organisation owners can update other members") case = get_case(case_id) user = User.objects.get( id=user_id, organisationuser__organisation=user_organisation) if not remove: user.assign_to_case(case=case, organisation=representing, created_by=request.user) user.contact.add_to_case( case=case, organisation=representing, primary=bool(primary), ) context = { "case_name": case.name, "case_number": case.reference, "company_name": user_organisation.name, "representing_clause": f" representing {representing.name}", "login_url": public_login_url(), } context[ "footer"] = "Investigations Team\r\nTrade Remedies\r\nDepartment for International Trade" # /PS-IGNORE context["full_name"] = user.contact.name or user.name audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "case": case, "user": user, "model": user.contact, } send_mail( email=user.contact.email, context=context, template_id=SystemParameter.get( "NOTIFY_USER_ASSIGNED_TO_CASE"), audit_kwargs=audit_kwargs, )
def send(self, sent_by, context=None, direct=False, template_key=None): """Send the invite email via notify Arguments: sent_by {User} -- The user sending the invitation Keyword Arguments: context {dict} -- extra context dict (default: {None}) direct {bool} -- include a direct login link with the invite codes (default: {False}) template_key {str} -- The system param pointing to the template id (default: {None}) Raises: InvitationFailure: raises if the invite is lacking a contact reference """ if not self.contact: raise InvitationFailure("No contact to invite") template_key = template_key or "NOTIFY_INFORM_INTERESTED_PARTIES" notify_template_id = SystemParameter.get(template_key) _context = { "organisation_name": self.organisation.name, "company_name": self.organisation.name, "full_name": self.contact.name, # invited contact "login_url": f"{settings.PUBLIC_ROOT_URL}", "guidance_url": SystemParameter.get("LINK_HELP_BOX_GUIDANCE"), "invited_by": self.created_by.name, } if self.case: product = self.case.product_set.first() export_source = self.case.exportsource_set.first() case_name = self.case.name or (product.sector.name if product else "N/A") _context.update({ "case_name": case_name, "case_number": self.case.reference, "investigation_type": self.case.type.name, "dumped_or_subsidised": self.case.dumped_or_subsidised(), "product": product.name, "country": export_source.country.name if export_source else None, "notice_url": self.submission.url if self.submission else "", # TODO: Remove "notice_of_initiation_url": self.case.latest_notice_of_initiation_url, "invited_by_name": self.submission.contact.name if self.submission else "", "invited_by_organisation": self.submission.organisation.name if self.submission else "", }) # Set email and footer appropriate to case context email = notify_contact_email(_context.get("case_number")) _context.update({"email": email, "footer": notify_footer(email)}) if direct is True: _context[ "login_url"] = f"{settings.PUBLIC_ROOT_URL}/invitation/{self.code}/{self.case.id}/" if context: _context.update(context) audit_kwargs = { "audit_type": AUDIT_TYPE_NOTIFY, "user": sent_by, "case": self.case, "model": self.contact, } send_mail(self.contact.email, _context, notify_template_id, audit_kwargs=audit_kwargs)