def send_sms_to_provider(notification): service = dao_fetch_service_by_id(notification.service_id) provider = provider_to_use(SMS_TYPE, notification.id) if notification.status == 'created': template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, sender=service.sms_sender ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: send_sms_response.apply_async( (provider.get_name(), str(notification.id), notification.to), queue='research-mode' ) notification.billable_units = 0 else: provider.send_sms( to=validate_and_format_phone_number(notification.to), content=str(template), reference=str(notification.id), sender=service.sms_sender ) notification.billable_units = template.fragment_count notification.sent_at = datetime.utcnow() notification.sent_by = provider.get_name() notification.status = 'sending' dao_update_notification(notification) current_app.logger.info( "SMS {} sent to provider at {}".format(notification.id, notification.sent_at) ) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("sms.total-time", delta_milliseconds)
def wrapper(*args, **kwargs): start_time = monotonic() res = func(*args, **kwargs) elapsed_time = monotonic() - start_time current_app.logger.info( "{namespace} call {func} took {time}".format( namespace=namespace, func=func.__name__, time="{0:.4f}".format(elapsed_time) ) ) statsd_client.incr('{namespace}.{func}'.format( namespace=namespace, func=func.__name__) ) statsd_client.timing('{namespace}.{func}'.format( namespace=namespace, func=func.__name__), elapsed_time ) return res
def send_email_to_provider(notification): service = dao_fetch_service_by_id(notification.service_id) provider = provider_to_use(EMAIL_TYPE, notification.id) if notification.status == 'created': template_dict = dao_get_template_by_id(notification.template_id, notification.template_version).__dict__ html_email = HTMLEmailTemplate( template_dict, values=notification.personalisation, **get_html_email_options(service) ) plain_text_email = PlainTextEmailTemplate( template_dict, values=notification.personalisation ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: reference = str(create_uuid()) send_email_response.apply_async( (provider.get_name(), reference, notification.to), queue='research-mode' ) notification.billable_units = 0 else: from_address = '"{}" <{}@{}>'.format(service.name, service.email_from, current_app.config['NOTIFY_EMAIL_DOMAIN']) reference = provider.send_email( from_address, notification.to, plain_text_email.subject, body=str(plain_text_email), html_body=str(html_email), reply_to_address=service.reply_to_email_address, ) notification.reference = reference notification.sent_at = datetime.utcnow() notification.sent_by = provider.get_name(), notification.status = 'sending' dao_update_notification(notification) current_app.logger.info( "Email {} sent to provider at {}".format(notification.id, notification.sent_at) ) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("email.total-time", delta_milliseconds)
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': # TODO: issue is that this does not get the provider based on who owns # the inbound number. The notification.reply_to_text below is the phone # number that we should send from, but we need to look at that and see # who the provider is. # TODO: now that we do get the right provider, the issue is that the # reply to text could be different because the service is able to choose # the sender when sending a message. So we need to check if the sender # ID that was chosen is also an inbound number. provider = None preferred_provider = get_preferred_sms_provider(service) if preferred_provider: provider = get_sms_provider_client(preferred_provider, notification.id) else: provider = provider_to_use(SMS_TYPE, notification.id, notification.international) current_app.logger.debug( "Starting sending SMS {} to provider at {}".format( notification.id, datetime.utcnow())) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.billable_units = 0 update_notification(notification, provider) try: send_sms_response(provider.get_name(), str(notification.id), notification.to) except HTTPError: # when we retry, we only do anything if the notification is in created - it's currently in sending, # so set it back so that we actually attempt the callback again notification.sent_at = None notification.sent_by = None notification.status = NOTIFICATION_CREATED dao_update_notification(notification) raise else: status = None try: reference, status = provider.send_sms( to=notification.normalised_to, content=str(template), reference=str(notification.id), sender=notification.reply_to_text) notification.reference = reference notification.billable_units = template.fragment_count # An international notification (i.e. a text message with an # abroad recipient phone number) instantly get marked as "sent". # It might later get marked as "delivered" when the provider # status callback is triggered. if notification.international: status = NOTIFICATION_SENT except Exception as e: dao_toggle_sms_provider(provider.name) raise e else: update_notification(notification, provider, status=status) current_app.logger.debug("SMS {} sent to provider {} at {}".format( notification.id, provider.get_name(), notification.sent_at)) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("sms.total-time", delta_milliseconds)
def send_email_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return # TODO: no else - replace with if statement raising error / logging when not 'created' if notification.status == 'created': provider = provider_to_use(EMAIL_TYPE, notification) # TODO: remove that code or extract attachment handling to separate method # Extract any file objects from the personalization file_keys = [ k for k, v in (notification.personalisation or {}).items() if isinstance(v, dict) and 'document' in v ] attachments = [] personalisation_data = notification.personalisation.copy() for key in file_keys: # Check if a MLWR sid exists if (current_app.config["MLWR_HOST"] and 'mlwr_sid' in personalisation_data[key]['document'] and personalisation_data[key]['document']['mlwr_sid'] != "false"): mlwr_result = check_mlwr( personalisation_data[key]['document']['mlwr_sid']) if "state" in mlwr_result and mlwr_result[ "state"] == "completed": # Update notification that it contains malware if "submission" in mlwr_result and mlwr_result[ "submission"]['max_score'] >= 500: malware_failure(notification=notification) return else: # Throw error so celery will retry in sixty seconds raise MalwarePendingException try: response = requests.get( personalisation_data[key]['document']['direct_file_url']) if response.headers['Content-Type'] == 'application/pdf': attachments.append({ "name": "{}.pdf".format(key), "data": response.content }) except Exception: current_app.logger.error( "Could not download and attach {}".format( personalisation_data[key]['document'] ['direct_file_url'])) personalisation_data[key] = personalisation_data[key]['document'][ 'url'] template_dict = dao_get_template_by_id( notification.template_id, notification.template_version).__dict__ html_email = HTMLEmailTemplate(template_dict, values=personalisation_data, **get_html_email_options( notification, provider)) plain_text_email = PlainTextEmailTemplate(template_dict, values=personalisation_data) if current_app.config["SCAN_FOR_PII"]: contains_pii(notification, str(plain_text_email)) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.reference = str(create_uuid()) update_notification_to_sending(notification, provider) send_email_response(notification.reference, notification.to) else: email_reply_to = notification.reply_to_text reference = provider.send_email( source=compute_source_email_address(service, provider), to_addresses=validate_and_format_email_address( notification.to), subject=plain_text_email.subject, body=str(plain_text_email), html_body=str(html_email), reply_to_address=validate_and_format_email_address( email_reply_to) if email_reply_to else None, attachments=attachments) notification.reference = reference update_notification_to_sending(notification, provider) current_app.logger.info( f"Saved provider reference: {reference} for notification id: {notification.id}" ) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("email.total-time", delta_milliseconds)
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': provider = provider_to_use(SMS_TYPE, notification.international) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: update_notification_to_sending(notification, provider) send_sms_response(provider.get_name(), str(notification.id), notification.to) else: try: response = provider.send_sms( to=validate_and_format_phone_number( notification.to, international=notification.international), content=str(template), reference=str(notification.id), sender=notification.reply_to_text) except Exception as e: notification.billable_units = template.fragment_count dao_update_notification(notification) dao_reduce_sms_provider_priority( provider.get_name(), time_threshold=timedelta(minutes=1)) raise e else: notification.billable_units = template.fragment_count if provider.get_name() == 'twilio': notification.reference = json.loads( response.content).get('sid') update_notification_to_sending(notification, provider) delta_seconds = (datetime.utcnow() - notification.created_at).total_seconds() statsd_client.timing("sms.total-time", delta_seconds) if notification.key_type == KEY_TYPE_TEST: statsd_client.timing("sms.test-key.total-time", delta_seconds) else: statsd_client.timing("sms.live-key.total-time", delta_seconds) if str(service.id) in current_app.config.get( 'HIGH_VOLUME_SERVICE'): statsd_client.timing("sms.live-key.high-volume.total-time", delta_seconds) else: statsd_client.timing("sms.live-key.not-high-volume.total-time", delta_seconds)