def resend_application_confirmation(self, request, queryset): resent_count = 0 for application in queryset: context = { "subject": NotificationType.BERTH_APPLICATION_CREATED.label, **application.get_notification_context(), } try: send_notification( application.email, NotificationType.BERTH_APPLICATION_CREATED.value, context, application.language, ) resent_count += 1 except (OSError, AnymailError): logger.error( "Failed to resend confirmation for berth application {}".format( application.id ) ) self.message_user( request, _("Resent confirmation for %d berth application(s)") % resent_count, messages.SUCCESS, )
def handle(self, *args, **options): email = options["email"] notification_type = options["notification_type"] custom_context = options["context"] if notification_data := get_notification_data(notification_type): notification_type = notification_data["notification_type"] default_context = notification_data["context"] notification = { "email": email, "language": "en", "context": { **default_context, **custom_context }, "notification_type": notification_type, } try: send_notification(**notification) self.stdout.write(self.style.SUCCESS("Notification sent")) self.stdout.write(json.dumps(notification, indent=2)) except Exception as e: self.stdout.write( self.style.ERROR(f"Error while sending notification: {e}"))
def mutate_and_get_payload(cls, root, info, **input): youth_data = input.get("approval_data") token = input.get("approval_token") youth_profile = YouthProfile.objects.get(approval_token=token) for field, value in youth_data.items(): setattr(youth_profile, field, value) try: email = youth_profile.profile.get_primary_email() except Email.DoesNotExist: raise ProfileHasNoPrimaryEmailError( "Cannot send email confirmation, youth profile has no primary email address." ) youth_profile.approved_time = timezone.now() youth_profile.approval_token = "" # invalidate youth_profile.save() send_notification( email=email.email, notification_type=NotificationType.YOUTH_PROFILE_CONFIRMED.value, context={"youth_profile": youth_profile}, language=youth_profile.profile.language if youth_profile.profile else "fi", ) return ApproveYouthProfileMutation(youth_profile=youth_profile)
def resend_application_confirmation(self, request, queryset): resent_count = 0 for application in queryset: try: notification_type = ( NotificationType.UNMARKED_WINTER_STORAGE_APPLICATION_CREATED if application.area_type == ApplicationAreaType.UNMARKED else NotificationType.WINTER_STORAGE_APPLICATION_CREATED ) context = { "subject": notification_type.label, **application.get_notification_context(), } send_notification( application.email, notification_type.value, context, application.language, ) resent_count += 1 except (OSError, AnymailError): logger.error( "Failed to resend confirmation for winter storage application {}".format( application.id ) ) self.message_user( request, _("Resent confirmation for %d winter storage application(s)") % resent_count, messages.SUCCESS, )
def make_approvable(self): self.approval_token = uuid.uuid4() send_notification( email=self.approver_email, notification_type=NotificationType. YOUTH_PROFILE_CONFIRMATION_NEEDED.value, context={"youth_profile": self}, language=self.language_at_home.value, ) self.approval_notification_timestamp = timezone.now()
def index(request): animal = Animal(name="Rox the Fox") context = { "animal": animal, "foo": "bar", } attachment = "test.txt", "foo bar", "text/plain" send_notification("*****@*****.**", "event_created", context, "en", [attachment]) return HttpResponse("Hello, world. You're at the polls index.")
def mutate_and_get_payload(cls, root, info, **input): youth_data = input.get("approval_data") token = input.get("approval_token") if not token: raise GraphQLError("Approval token cannot be empty.") youth_profile = YouthProfile.objects.get(approval_token=token) if (not youth_profile.profile_access_token or youth_profile.profile_access_token_expiration < timezone.now()): raise TokenExpiredError( "Profile access token is expired or not set.") profile_api = ProfileAPI() profile_data = profile_api.fetch_profile_with_temporary_access_token( youth_profile.profile_access_token) if not profile_data["email"]: raise ProfileHasNoPrimaryEmailError( "Cannot send email confirmation, youth profile has no primary email address." ) contact_persons_to_create = youth_data.pop( "add_additional_contact_persons", []) contact_persons_to_update = youth_data.pop( "update_additional_contact_persons", []) contact_persons_to_delete = youth_data.pop( "remove_additional_contact_persons", []) for field, value in youth_data.items(): setattr(youth_profile, field, value) # Additional contact persons create_or_update_contact_persons(youth_profile, contact_persons_to_create) create_or_update_contact_persons(youth_profile, contact_persons_to_update) delete_contact_persons(youth_profile, contact_persons_to_delete) youth_profile.set_approved() youth_profile.save() send_notification( email=profile_data["email"], notification_type=NotificationType.YOUTH_PROFILE_CONFIRMED.value, context={ "youth_profile": youth_profile, "youth_name": profile_data["first_name"], "youth_membership_ui_base_url": settings.EMAIL_TEMPLATE_YOUTH_MEMBERSHIP_UI_BASE_URL, }, language=profile_data["language"], ) return ApproveYouthProfileMutation(youth_profile=youth_profile)
def make_approvable(self, youth_name: str): self.approval_token = uuid.uuid4() send_notification( email=self.approver_email, notification_type=NotificationType.YOUTH_PROFILE_CONFIRMATION_NEEDED.value, context={ "youth_profile": self, "youth_name": youth_name, "youth_membership_ui_base_url": settings.EMAIL_TEMPLATE_YOUTH_MEMBERSHIP_UI_BASE_URL, }, language=self.language_at_home.value, ) self.approval_notification_timestamp = timezone.now()
def test_translated_from_email(notification_template, settings, language): context = { "extra_var": "foo", "subject_var": "bar", "body_html_var": "html_baz", "body_text_var": "text_baz", } settings.ILMOITIN_TRANSLATED_FROM_EMAIL = {"fi": "Yrjö <*****@*****.**>"} send_notification("*****@*****.**", "event_created", context, language) assert len(mail.outbox) == 1 message = mail.outbox[0] assert message.from_email == settings.ILMOITIN_TRANSLATED_FROM_EMAIL.get( language, settings.DEFAULT_FROM_EMAIL )
def email_admins(self, exited_with_errors: bool = False): logger.debug("Emailing admins") context = { "subject": LeaseNotificationType.AUTOMATIC_INVOICING_EMAIL_ADMINS.label, "exited_with_errors": exited_with_errors, "successful_orders": len(self.successful_orders), "failed_orders": self.number_of_failed_orders, } admins = (get_user_model().objects.filter(groups=Group.objects.get( name=self.ADMIN_EMAIL_NOTIFICATION_GROUP_NAME)).exclude( email="").exclude(email__icontains="@example.com")) for admin in admins: send_notification( admin.email, LeaseNotificationType.AUTOMATIC_INVOICING_EMAIL_ADMINS, context, )
def application_notification_handler(sender, application, **kwargs): notification_type = NotificationType.BERTH_APPLICATION_CREATED if sender == MARKED_WS_SENDER: notification_type = NotificationType.WINTER_STORAGE_APPLICATION_CREATED elif sender == UNMARKED_WS_SENDER: notification_type = NotificationType.UNMARKED_WINTER_STORAGE_APPLICATION_CREATED elif sender == REJECT_BERTH_SENDER: notification_type = NotificationType.BERTH_APPLICATION_REJECTED context = { "subject": notification_type.label, **application.get_notification_context(), } try: send_notification( application.email, notification_type.value, context, application.language, ) except (OSError, AnymailError) as e: capture_exception(e)
def test_notification_delayed_sending(notification_template): context = { "extra_var": "foo", "subject_var": "bar", "body_html_var": "html_baz", "body_text_var": "text_baz", } # Override settings to use django-mailer email backend settings.EMAIL_BACKEND = "mailer.backend.DbBackend" settings.MAILER_EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.ILMOITIN_QUEUE_NOTIFICATIONS = True send_notification("*****@*****.**", "event_created", context, "fi") assert len(mail.outbox) == 0 assert Message.objects.count() == 1 # Now actually send emails Message.objects.retry_deferred() send_all() assert Message.objects.count() == 0 assert len(mail.outbox) == 1
def test_notification_sending(notification_template): context = { "extra_var": "foo", "subject_var": "bar", "body_html_var": "html_baz", "body_text_var": "text_baz", } send_notification("*****@*****.**", "event_created", context, "fi") assert len(mail.outbox) == 1 message = mail.outbox[0] subject = message.subject body_html = next(a[0] for a in message.alternatives if a[1] == "text/html") body_text = message.body assert message.to == ["*****@*****.**"] assert message.from_email == settings.DEFAULT_FROM_EMAIL assert subject == "testiotsikko, muuttujan arvo: bar!" assert body_html == "<b>testihötömölöruumis</b>, muuttujan arvo: html_baz!" assert body_text == "testitekstiruumis, muuttujan arvo: text_baz!"
def send_berth_switch_offer( offer, due_date: date, ) -> None: if due_date: offer.due_date = due_date offer.save() # Update offer and application status offer.set_status(OfferStatus.OFFERED) from .notifications import NotificationType language = (offer.application.language if offer.application else settings.LANGUAGE_CODE) email = offer.customer_email or offer.application.email if not is_valid_email(email): raise ValidationError(_("Missing customer email")) notification_type = NotificationType.BERTH_SWITCH_OFFER_APPROVED context = { "subject": get_email_subject(notification_type), "offer": offer, "accept_url": get_offer_customer_url(offer, language, True), "cancel_url": get_offer_customer_url(offer, language, False), "due_date": format_date(offer.due_date, locale=language), } send_notification(email, notification_type.value, context, language) if offer.customer_phone: sms_service = SMSNotificationService() sms_service.send( NotificationType.SMS_BERTH_SWITCH_NOTICE, context, offer.customer_phone, language=language, )
def send_refund_notice(order): from .notifications import NotificationType language = (order.lease.application.language if order.lease and order.lease.application else settings.LANGUAGE_CODE) notification_type = NotificationType.ORDER_REFUNDED context = get_context(order, notification_type, has_services=False, payment_url=None, cancel_url=None) email = order.customer_email if not email: if order.lease and order.lease.application: email = order.lease.application.email else: raise VenepaikkaGraphQLError(_("No email was found")) send_notification(email, notification_type.value, context, language)
def relationship_saved_handler(sender, instance, created, **kwargs): confirmed = instance.confirmation_degree != RepresentativeConfirmationDegree.NONE # Only notify person whose confirmation is needed if created and not confirmed: try: send_notification( instance.representative.email, NotificationType.RELATIONSHIP_CONFIRMATION_NEEDED.value, instance.get_notification_context(), instance.representative.language, ) except (OSError, AnymailError) as e: capture_exception(e) # Notify both parties involved elif confirmed: try: send_notification( instance.representative.email, NotificationType.RELATIONSHIP_CONFIRMED.value, instance.get_notification_context(), instance.representative.language, ) except (OSError, AnymailError) as e: capture_exception(e) try: send_notification( instance.representee.email, NotificationType.RELATIONSHIP_CONFIRMED.value, instance.get_notification_context(), instance.representee.language, ) except (OSError, AnymailError) as e: capture_exception(e)
def terminate_lease( lease: Union[BerthLease, WinterStorageLease], end_date: date = None, profile_token: str = None, send_notice: bool = True, ) -> Union[BerthLease, WinterStorageLease]: from .models import BerthLease from .notifications import NotificationType if lease.status not in TERMINABLE_STATUSES: raise ValidationError( _( f"Only leases in paid, error or offered status can be terminated, current status is {lease.status}" ) ) for order in lease.orders.all(): if order.status in OrderStatus.get_waiting_statuses(): order.set_status(OrderStatus.CANCELLED, _("Lease was terminated")) lease.status = LeaseStatus.TERMINATED if isinstance(lease, BerthLease): default_date = calculate_berth_lease_start_date() else: # WinterStorageLease default_date = calculate_winter_storage_lease_start_date() lease.end_date = end_date or default_date lease.save() if send_notice: language = ( lease.application.language if lease.application else settings.LANGUAGES[0][0] ) email = None if profile_token: profile_service = ProfileService(profile_token=profile_token) profile = profile_service.get_profile(lease.customer.id) email = profile.email if not email and lease.application: email = lease.application.email if not email: raise ValidationError( _("The lease has no email and no profile token was provided") ) if not is_valid_email(email): raise ValidationError(_("Missing customer email")) notification_type = ( NotificationType.BERTH_LEASE_TERMINATED_LEASE_NOTICE if isinstance(lease, BerthLease) else NotificationType.WINTER_STORAGE_LEASE_TERMINATED_LEASE_NOTICE ) send_notification( email, notification_type, { "subject": notification_type.label, "cancelled_at": format_date(today(), locale=language), "lease": lease, }, language=language, ) return lease
notification_type = NotificationType.ORDER_CANCELLED if rejected_at := getattr(order, "rejected_at", None): rejected_at = format_date(rejected_at, locale=language) context = { "order": order, "rejected_at": rejected_at, "subject": get_email_subject(notification_type), } email = order.customer_email if not email: if order.lease and order.lease.application: email = order.lease.application.email else: raise VenepaikkaGraphQLError(_("No email was found")) send_notification(email, notification_type.value, context, language) def send_refund_notice(order): from .notifications import NotificationType language = (order.lease.application.language if order.lease and order.lease.application else settings.LANGUAGE_CODE) notification_type = NotificationType.ORDER_REFUNDED context = get_context(order, notification_type, has_services=False, payment_url=None, cancel_url=None)
def send_payment_notification( order: Order, request: HttpRequest, email: str = None, phone_number: str = None, has_services: bool = True, has_payment_urls: bool = True, ): from payments.providers import get_payment_provider from .notifications import NotificationType order_email = email or order.customer_email order_phone = phone_number or order.customer_phone if not is_valid_email(order_email): raise ValidationError(_("Missing customer email")) language = get_notification_language(order) payment_url = None cancel_url = None if has_payment_urls: payment_url = get_payment_provider( request, ui_return_url=settings.VENE_UI_RETURN_URL).get_payment_email_url( order, lang=language) cancel_url = get_payment_provider( request, ui_return_url=settings.VENE_UI_RETURN_URL ).get_cancellation_email_url(order, lang=language) notification_type = get_order_notification_type(order) context = get_context(order, notification_type, has_services, payment_url, cancel_url) send_notification(order_email, notification_type.value, context, language) if order_phone and notification_type not in ( NotificationType.ORDER_CANCELLED, NotificationType.ORDER_REFUNDED, ): if hasattr(order, "product") and order.product: product_name = order.product.name else: product_name = ", ".join([ str(ProductServiceType(order_line.product.service).label) for order_line in order.order_lines.all() ]) sms_context = { "product_name": product_name, "due_date": format_date(order.due_date, locale=language), "payment_url": payment_url, } sms_service = SMSNotificationService() sms_service.send( NotificationType.SMS_INVOICE_NOTICE, sms_context, order_phone, language=language, )