def test_persist_notification_with_optionals(sample_job, sample_api_key, mocker): assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr') n_id = uuid.uuid4() created_at = datetime.datetime(2016, 11, 11, 16, 8, 18) persist_notification(template_id=sample_job.template.id, template_version=sample_job.template.version, recipient='+447111111111', service_id=sample_job.service.id, personalisation=None, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, created_at=created_at, job_id=sample_job.id, job_row_number=10, reference="ref from client", notification_id=n_id) assert Notification.query.count() == 1 assert NotificationHistory.query.count() == 1 persisted_notification = Notification.query.all()[0] assert persisted_notification.id == n_id persisted_notification.job_id == sample_job.id assert persisted_notification.job_row_number == 10 assert persisted_notification.created_at == created_at mocked_redis.assert_called_once_with(str(sample_job.service_id) + "-2016-01-01-count") assert persisted_notification.client_reference == "ref from client" assert persisted_notification.reference is None
def test_cache_is_not_incremented_on_failure_to_persist_notification(sample_api_key, mocker): mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr') with pytest.raises(SQLAlchemyError): persist_notification(template_id=None, template_version=None, recipient='+447111111111', service_id=sample_api_key.service_id, personalisation=None, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type) mocked_redis.assert_not_called()
def test_persist_notification_throws_exception_when_missing_template(sample_api_key): assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 with pytest.raises(SQLAlchemyError): persist_notification(template_id=None, template_version=None, recipient='+447111111111', service_id=sample_api_key.service_id, personalisation=None, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type) assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0
def post_email_notification(): form = validate(request.get_json(), post_email_request) service = services_dao.dao_fetch_service_by_id(api_user.service_id) check_service_message_limit(api_user.key_type, service) service_can_send_to_recipient(form["email_address"], api_user.key_type, service) template, template_with_content = __validate_template(form, service, EMAIL_TYPE) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=form["email_address"], service_id=service.id, personalisation=form.get("personalisation", None), notification_type=EMAIL_TYPE, api_key_id=api_user.id, key_type=api_user.key_type, reference=form.get("reference"), ) send_notification_to_queue(notification, service.research_mode) resp = create_post_email_response_from_notification( notification=notification, content=str(template_with_content), subject=template_with_content.subject, email_from=service.email_from, url_root=request.url_root, ) return jsonify(resp), 201
def test_persist_notification_creates_and_save_to_db(sample_template, sample_api_key, sample_job, mocker): mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr') assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 notification = persist_notification(sample_template.id, sample_template.version, '+447111111111', sample_template.service.id, {}, 'sms', sample_api_key.id, sample_api_key.key_type, job_id=sample_job.id, job_row_number=100, reference="ref") assert Notification.query.get(notification.id) is not None assert NotificationHistory.query.get(notification.id) is not None notification_from_db = Notification.query.one() notification_history_from_db = NotificationHistory.query.one() assert notification_from_db.id == notification_history_from_db.id assert notification_from_db.template_id == notification_history_from_db.template_id assert notification_from_db.template_version == notification_history_from_db.template_version assert notification_from_db.api_key_id == notification_history_from_db.api_key_id assert notification_from_db.key_type == notification_history_from_db.key_type assert notification_from_db.key_type == notification_history_from_db.key_type assert notification_from_db.billable_units == notification_history_from_db.billable_units assert notification_from_db.notification_type == notification_history_from_db.notification_type assert notification_from_db.created_at == notification_history_from_db.created_at assert not notification_from_db.sent_at assert not notification_history_from_db.sent_at assert notification_from_db.updated_at == notification_history_from_db.updated_at assert notification_from_db.status == notification_history_from_db.status assert notification_from_db.reference == notification_history_from_db.reference assert notification_from_db.client_reference == notification_history_from_db.client_reference mocked_redis.assert_called_once_with(str(sample_template.service_id) + "-2016-01-01-count")
def post_sms_notification(): form = validate(request.get_json(), post_sms_request) service = services_dao.dao_fetch_service_by_id(api_user.service_id) check_service_message_limit(api_user.key_type, service) service_can_send_to_recipient(form["phone_number"], api_user.key_type, service) template, template_with_content = __validate_template(form, service, SMS_TYPE) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=form["phone_number"], service_id=service.id, personalisation=form.get("personalisation", None), notification_type=SMS_TYPE, api_key_id=api_user.id, key_type=api_user.key_type, reference=form.get("reference"), ) send_notification_to_queue(notification, service.research_mode) sms_sender = service.sms_sender if service.sms_sender else current_app.config.get("FROM_NUMBER") resp = create_post_sms_response_from_notification( notification, str(template_with_content), sms_sender, request.url_root ) return jsonify(resp), 201
def send_user_sms_code(user_id): user_to_send_to = get_user_by_id(user_id=user_id) verify_code, errors = request_verify_code_schema.load(request.get_json()) secret_code = create_secret_code() create_user_code(user_to_send_to, secret_code, SMS_TYPE) mobile = user_to_send_to.mobile_number if verify_code.get('to', None) is None else verify_code.get('to') sms_code_template_id = current_app.config['SMS_CODE_TEMPLATE_ID'] sms_code_template = dao_get_template_by_id(sms_code_template_id) notify_service_id = current_app.config['NOTIFY_SERVICE_ID'] saved_notification = persist_notification( template_id=sms_code_template_id, template_version=sms_code_template.version, recipient=mobile, service_id=notify_service_id, personalisation={'verify_code': secret_code}, notification_type=SMS_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL ) # Assume that we never want to observe the Notify service's research mode # setting for this notification - we still need to be able to log into the # admin even if we're doing user research using this service: send_notification_to_queue(saved_notification, False, queue='notify') return jsonify({}), 204
def send_user_confirm_new_email(user_id): user_to_send_to = get_user_by_id(user_id=user_id) email, errors = email_data_request_schema.load(request.get_json()) if errors: raise InvalidRequest(message=errors, status_code=400) template = dao_get_template_by_id(current_app.config['CHANGE_EMAIL_CONFIRMATION_TEMPLATE_ID']) notify_service_id = current_app.config['NOTIFY_SERVICE_ID'] saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=email['email'], service_id=notify_service_id, personalisation={ 'name': user_to_send_to.name, 'url': _create_confirmation_url(user=user_to_send_to, email_address=email['email']), 'feedback_url': current_app.config['ADMIN_BASE_URL'] + '/feedback' }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL ) send_notification_to_queue(saved_notification, False, queue='notify') return jsonify({}), 204
def send_sms( self, service_id, notification_id, encrypted_notification, created_at, api_key_id=None, key_type=KEY_TYPE_NORMAL ): notification = encryption.decrypt(encrypted_notification) service = dao_fetch_service_by_id(service_id) if not service_allowed_to_send_to(notification["to"], service, key_type): current_app.logger.info("SMS {} failed as restricted service".format(notification_id)) return try: saved_notification = persist_notification( template_id=notification["template"], template_version=notification["template_version"], recipient=notification["to"], service_id=service.id, personalisation=notification.get("personalisation"), notification_type=SMS_TYPE, api_key_id=api_key_id, key_type=key_type, created_at=created_at, job_id=notification.get("job", None), job_row_number=notification.get("row_number", None), notification_id=notification_id, ) provider_tasks.deliver_sms.apply_async( [str(saved_notification.id)], queue="send-sms" if not service.research_mode else "research-mode" ) current_app.logger.info( "SMS {} created at {} for job {}".format(saved_notification.id, created_at, notification.get("job", None)) ) except SQLAlchemyError as e: if not get_notification_by_id(notification_id): # Sometimes, SQS plays the same message twice. We should be able to catch an IntegrityError, but it seems # SQLAlchemy is throwing a FlushError. So we check if the notification id already exists then do not # send to the retry queue. current_app.logger.error( "RETRY: send_sms notification for job {} row number {} and notification id {}".format( notification.get("job", None), notification.get("row_number", None), notification_id ) ) current_app.logger.exception(e) try: raise self.retry(queue="retry", exc=e) except self.MaxRetriesExceededError: current_app.logger.error( "RETRY FAILED: send_sms notification for job {} row number {} and notification id {}".format( notification.get("job", None), notification.get("row_number", None), notification_id ) ) current_app.logger.exception(e)
def test_persist_notification_increments_cache_if_key_exists( sample_template, sample_api_key, mocker): mock_incr = mocker.patch( 'app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1) mocker.patch( 'app.notifications.process_notifications.redis_store.get_all_from_hash', return_value={sample_template.id, 1}) persist_notification(template_id=sample_template.id, template_version=sample_template.version, recipient='+447111111122', service=sample_template.service, personalisation={}, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, reference="ref2") mock_incr.assert_called_once_with( str(sample_template.service_id) + "-2016-01-01-count", )
def test_persist_email_notification_stores_normalised_email( sample_job, sample_api_key, mocker, recipient, expected_recipient_normalised ): persist_notification( template_id=sample_job.template.id, template_version=sample_job.template.version, recipient=recipient, service=sample_job.service, personalisation=None, notification_type='email', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, job_id=sample_job.id, ) persisted_notification = Notification.query.all()[0] assert persisted_notification.to == recipient assert persisted_notification.normalised_to == expected_recipient_normalised
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist(sample_template, sample_api_key, mocker): mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mock_incr_hash_value = mocker.patch('app.notifications.process_notifications.redis_store.increment_hash_value') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=None) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value=None) persist_notification( template_id=sample_template.id, template_version=sample_template.version, recipient='+61412345678', service=sample_template.service, personalisation={}, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, reference="ref" ) mock_incr.assert_not_called() mock_incr_hash_value.assert_called_once_with( "service-{}-template-usage-2016-01-01".format(sample_template.service_id), sample_template.id )
def send_one_off_notification(service_id, post_data): service = dao_fetch_service_by_id(service_id) template = dao_get_template_by_id_and_service_id( template_id=post_data['template_id'], service_id=service_id ) personalisation = post_data.get('personalisation', None) validate_template(template.id, personalisation, service, template.template_type) check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) validate_and_format_recipient( send_to=post_data['to'], key_type=KEY_TYPE_NORMAL, service=service, notification_type=template.template_type, allow_whitelisted_recipients=False, ) validate_created_by(service, post_data['created_by']) sender_id = post_data.get('sender_id', None) reply_to = get_reply_to_text( notification_type=template.template_type, sender_id=sender_id, service=service, template=template ) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=post_data['to'], service=service, personalisation=personalisation, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, created_by_id=post_data['created_by'], reply_to_text=reply_to ) queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None send_notification_to_queue( notification=notification, research_mode=service.research_mode, queue=queue_name ) return {'id': str(notification.id)}
def save_email(self, service_id, notification_id, encrypted_notification, sender_id=None): notification = encryption.decrypt(encrypted_notification) service = SerialisedService.from_id(service_id) template = SerialisedTemplate.from_id_and_service_id( notification['template'], service_id=service.id, version=notification['template_version'], ) if sender_id: reply_to_text = dao_get_reply_to_by_id(service_id, sender_id).email_address else: reply_to_text = template.reply_to_text if not service_allowed_to_send_to(notification['to'], service, KEY_TYPE_NORMAL): current_app.logger.info( "Email {} failed as restricted service".format(notification_id)) return try: saved_notification = persist_notification( template_id=notification['template'], template_version=notification['template_version'], recipient=notification['to'], service=service, personalisation=notification.get('personalisation'), notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, created_at=datetime.utcnow(), job_id=notification.get('job', None), job_row_number=notification.get('row_number', None), notification_id=notification_id, reply_to_text=reply_to_text) provider_tasks.deliver_email.apply_async( [str(saved_notification.id)], queue=QueueNames.SEND_EMAIL if not service.research_mode else QueueNames.RESEARCH_MODE) current_app.logger.debug("Email {} created at {}".format( saved_notification.id, saved_notification.created_at)) except SQLAlchemyError as e: handle_exception(self, notification, notification_id, e)
def process_sms_or_email_notification(*, form, notification_type, api_key, template, service, reply_to_text=None): form_send_to = form[ 'email_address'] if notification_type == EMAIL_TYPE else form[ 'phone_number'] send_to = validate_and_format_recipient( send_to=form_send_to, key_type=api_key.key_type, service=service, notification_type=notification_type) # Do not persist or send notification to the queue if it is a simulated recipient simulated = simulated_recipient(send_to, notification_type) personalisation = process_document_uploads(form.get('personalisation'), service, simulated=simulated) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=form_send_to, service=service, personalisation=personalisation, notification_type=notification_type, api_key_id=api_key.id, key_type=api_key.key_type, client_reference=form.get('reference', None), simulated=simulated, reply_to_text=reply_to_text, recipient_identifier=form.get('recipient_identifier', None)) scheduled_for = form.get("scheduled_for", None) if scheduled_for: persist_scheduled_notification(notification.id, form["scheduled_for"]) else: if simulated: current_app.logger.debug( "POST simulated notification for id: {}".format( notification.id)) else: queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None send_notification_to_queue(notification=notification, research_mode=service.research_mode, queue=queue_name) return notification
def test_persist_notification_with_optionals(sample_job, sample_api_key, mocker): assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 mocked_redis = mocker.patch( 'app.notifications.process_notifications.redis_store.get') n_id = uuid.uuid4() created_at = datetime.datetime(2016, 11, 11, 16, 8, 18) persist_notification(template_id=sample_job.template.id, template_version=sample_job.template.version, recipient='+447111111111', service=sample_job.service, personalisation=None, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, created_at=created_at, job_id=sample_job.id, job_row_number=10, client_reference="ref from client", notification_id=n_id, created_by_id=sample_job.created_by_id) assert Notification.query.count() == 1 assert NotificationHistory.query.count() == 0 persisted_notification = Notification.query.all()[0] assert persisted_notification.id == n_id persisted_notification.job_id == sample_job.id assert persisted_notification.job_row_number == 10 assert persisted_notification.created_at == created_at mocked_redis.assert_called_once_with( str(sample_job.service_id) + "-2016-01-01-count") assert persisted_notification.client_reference == "ref from client" assert persisted_notification.reference is None assert persisted_notification.international is False assert persisted_notification.phone_prefix == '44' assert persisted_notification.rate_multiplier == 1 assert persisted_notification.created_by_id == sample_job.created_by_id assert not persisted_notification.reply_to_text
def test_persist_letter_notification_finds_correct_postage( mocker, notify_db, notify_db_session, postage_argument, template_postage, expected_postage): service = create_service(service_permissions=[LETTER_TYPE]) api_key = create_api_key(notify_db, notify_db_session, service=service) template = create_template(service, template_type=LETTER_TYPE, postage=template_postage) mocker.patch('app.dao.templates_dao.dao_get_template_by_id', return_value=template) persist_notification(template_id=template.id, template_version=template.version, template_postage=template.postage, recipient="Jane Doe, 10 Downing Street, London", service=service, personalisation=None, notification_type=LETTER_TYPE, api_key_id=api_key.id, key_type=api_key.key_type, postage=postage_argument) persisted_notification = Notification.query.all()[0] assert persisted_notification.postage == expected_postage
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist( notify_db_session, mocker): service = create_service(restricted=True) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch( 'app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=None) mocker.patch( 'app.notifications.process_notifications.redis_store.get_all_from_hash', return_value=None) persist_notification(template_id=template.id, template_version=template.version, recipient='+447111111111', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref") mock_incr.assert_not_called()
def update_service(service_id): req_json = request.get_json() fetched_service = dao_fetch_service_by_id(service_id) # Capture the status change here as Marshmallow changes this later service_going_live = fetched_service.restricted and not req_json.get('restricted', True) service_go_live_requested = 'go_live_user' in req_json current_data = dict(service_schema.dump(fetched_service).data.items()) current_data.update(request.get_json()) service = service_schema.load(current_data).data if 'email_branding' in req_json: email_branding_id = req_json['email_branding'] service.email_branding = None if not email_branding_id else EmailBranding.query.get(email_branding_id) if 'letter_branding' in req_json: letter_branding_id = req_json['letter_branding'] service.letter_branding = None if not letter_branding_id else LetterBranding.query.get(letter_branding_id) dao_update_service(service) if service_go_live_requested: template = dao_get_template_by_id(current_app.config['NOTIFY_ADMIN_OF_GO_LIVE_REQUEST_TEMPLATE_ID']) service_url = "{}/services/{}".format(current_app.config['ADMIN_BASE_URL'], str(service.id)) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=get_or_build_support_email_address(), service=template.service, personalisation={ 'service_name': service.name, 'service_dashboard_url': service_url }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=get_or_build_support_email_address() ) send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY) if service_going_live: send_notification_to_service_users( service_id=service_id, template_id=current_app.config['SERVICE_NOW_LIVE_TEMPLATE_ID'], personalisation={ 'service_name': current_data['name'], 'message_limit': '{:,}'.format(current_data['message_limit']) }, include_user_fields=['name'] ) return jsonify(data=service_schema.dump(fetched_service).data), 200
def test_persist_notification_does_not_increments_cache_live_service( notify_db_session, mocker ): service = create_service(restricted=False) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value={template.id, 1}) persist_notification( template_id=template.id, template_version=template.version, recipient='+447111111122', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref2") assert not mock_incr.called
def test_persist_notification_increments_cache_if_key_exists_and_for_trial_service( notify_db_session, mocker ): service = create_service(restricted=True) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value={template.id, 1}) persist_notification( template_id=template.id, template_version=template.version, recipient='+447111111122', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref2") mock_incr.assert_called_once_with(str(service.id) + "-2016-01-01-count", )
def test_persist_notification_with_international_info_does_not_store_for_email( sample_job, sample_api_key, mocker ): persist_notification( template_id=sample_job.template.id, template_version=sample_job.template.version, recipient='*****@*****.**', service=sample_job.service, personalisation=None, notification_type='email', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, job_id=sample_job.id, job_row_number=10, client_reference="ref from client" ) persisted_notification = Notification.query.all()[0] assert persisted_notification.international is False assert persisted_notification.phone_prefix is None assert persisted_notification.rate_multiplier is None
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist( sample_template, sample_api_key, mocker): mock_incr = mocker.patch( "app.notifications.process_notifications.redis_store.incr") mocker.patch("app.notifications.process_notifications.redis_store.get", return_value=None) mocker.patch( "app.notifications.process_notifications.redis_store.get_all_from_hash", return_value=None, ) persist_notification( template_id=sample_template.id, template_version=sample_template.version, recipient="+16502532222", service=sample_template.service, personalisation={}, notification_type="sms", api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, reference="ref", ) mock_incr.assert_not_called()
def test_persist_notification_does_not_increment_cache_if_test_key( notify_db, notify_db_session, sample_template, sample_job, mocker): api_key = create_api_key(notify_db=notify_db, notify_db_session=notify_db_session, service=sample_template.service, key_type='test') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value="cache") mocker.patch( 'app.notifications.process_notifications.redis_store.get_all_from_hash', return_value="cache") daily_limit_cache = mocker.patch( 'app.notifications.process_notifications.redis_store.incr') template_usage_cache = mocker.patch( 'app.notifications.process_notifications.redis_store.increment_hash_value' ) assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 persist_notification( template_id=sample_template.id, template_version=sample_template.version, recipient='+61412345678', service=sample_template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, job_id=sample_job.id, job_row_number=100, reference="ref", ) assert Notification.query.count() == 1 assert not daily_limit_cache.called assert not template_usage_cache.called
def test_should_delete_notification_and_recipient_identifiers_when_bulk_deleting( month, delete_run_time, notification_type, expected_count, sample_job, sample_api_key, mocker): mocker.patch( 'app.notifications.process_notifications.accept_recipient_identifiers_enabled', return_value=True) # create one notification a day between 1st and 10th from 11:00 to 19:00 of each type for i in range(1, 11): past_date = '2016-0{0}-{1:02d} {1:02d}:00:00.000000'.format(month, i) with freeze_time(past_date): recipient_identifier = { "id_type": IdentifierType.VA_PROFILE_ID.value, "id_value": "foo" } persist_notification(template_id=sample_job.template.id, template_version=sample_job.template.version, service=sample_job.service, personalisation=None, notification_type=notification_type, api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, recipient_identifier=recipient_identifier, created_at=datetime.utcnow()) assert Notification.query.count() == 10 assert RecipientIdentifier.query.count() == 10 # Records from before 3rd should be deleted with freeze_time(delete_run_time): delete_notifications_older_than_retention_by_type(notification_type) remaining_notifications = Notification.query.filter_by( notification_type=notification_type).all() assert len(remaining_notifications) == expected_count remaining_recipient_identifiers = len(RecipientIdentifier.query.all()) assert remaining_recipient_identifiers == expected_count
def send_letters_volume_email_to_dvla(letters_volumes, date): personalisation = { 'total_volume': 0, 'first_class_volume': 0, 'second_class_volume': 0, 'international_volume': 0, 'total_sheets': 0, 'first_class_sheets': 0, "second_class_sheets": 0, 'international_sheets': 0, 'date': date.strftime("%d %B %Y") } for item in letters_volumes: personalisation['total_volume'] += item.letters_count personalisation['total_sheets'] += item.sheets_count if f"{item.postage}_class_volume" in personalisation: personalisation[ f"{item.postage}_class_volume"] = item.letters_count personalisation[f"{item.postage}_class_sheets"] = item.sheets_count else: personalisation["international_volume"] += item.letters_count personalisation["international_sheets"] += item.sheets_count template = dao_get_template_by_id( current_app.config['LETTERS_VOLUME_EMAIL_TEMPLATE_ID']) recipients = current_app.config['DVLA_EMAIL_ADDRESSES'] reply_to = template.service.get_default_reply_to_email_address() service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID']) # avoid circular imports: from app.notifications.process_notifications import ( persist_notification, send_notification_to_queue, ) for recipient in recipients: saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=recipient, service=service, personalisation=personalisation, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=reply_to) send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY)
def test_persist_notification_creates_and_save_to_db(sample_template, sample_api_key, sample_job, mocker): mocked_redis = mocker.patch( 'app.notifications.process_notifications.redis_store.get') assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 notification = persist_notification( template_id=sample_template.id, template_version=sample_template.version, recipient='+61412345678', service=sample_template.service, personalisation={}, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, job_id=sample_job.id, job_row_number=100, reference="ref", reply_to_text=sample_template.service.get_default_sms_sender()) assert Notification.query.get(notification.id) is not None assert NotificationHistory.query.get(notification.id) is not None notification_from_db = Notification.query.one() notification_history_from_db = NotificationHistory.query.one() assert notification_from_db.id == notification_history_from_db.id assert notification_from_db.template_id == notification_history_from_db.template_id assert notification_from_db.template_version == notification_history_from_db.template_version assert notification_from_db.api_key_id == notification_history_from_db.api_key_id assert notification_from_db.key_type == notification_history_from_db.key_type assert notification_from_db.key_type == notification_history_from_db.key_type assert notification_from_db.billable_units == notification_history_from_db.billable_units assert notification_from_db.notification_type == notification_history_from_db.notification_type assert notification_from_db.created_at == notification_history_from_db.created_at assert not notification_from_db.sent_at assert not notification_history_from_db.sent_at assert notification_from_db.updated_at == notification_history_from_db.updated_at assert notification_from_db.status == notification_history_from_db.status assert notification_from_db.reference == notification_history_from_db.reference assert notification_from_db.client_reference == notification_history_from_db.client_reference assert notification_from_db.created_by_id == notification_history_from_db.created_by_id assert notification_from_db.reply_to_text == sample_template.service.get_default_sms_sender( ) mocked_redis.assert_called_once_with( str(sample_template.service_id) + "-2016-01-01-count")
def _send_notification(template_id, recipient, personalisation): template = dao_get_template_by_id(template_id) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=recipient, service=notify_service, personalisation=personalisation, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=notify_service.get_default_reply_to_email_address() ) send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY)
def test_persist_notification_for_international_letter(sample_letter_template, postage): notification = persist_notification( template_id=sample_letter_template.id, template_version=sample_letter_template.version, recipient="123 Main Street", service=sample_letter_template.service, personalisation=None, notification_type=sample_letter_template.template_type, api_key_id=None, key_type="normal", billable_units=3, postage=postage, ) persisted_notification = Notification.query.get(notification.id) assert persisted_notification.postage == postage assert persisted_notification.international
def save_sms(self, service_id, notification_id, encrypted_notification, api_key_id=None, key_type=KEY_TYPE_NORMAL): notification = encryption.decrypt(encrypted_notification) service = dao_fetch_service_by_id(service_id) template = dao_get_template_by_id(notification['template'], version=notification['template_version']) if not service_allowed_to_send_to(notification['to'], service, key_type): current_app.logger.debug( "SMS {} failed as restricted service".format(notification_id) ) return try: saved_notification = persist_notification( template_id=notification['template'], template_version=notification['template_version'], recipient=notification['to'], service=service, personalisation=notification.get('personalisation'), notification_type=SMS_TYPE, api_key_id=api_key_id, key_type=key_type, created_at=datetime.utcnow(), job_id=notification.get('job', None), job_row_number=notification.get('row_number', None), notification_id=notification_id, reply_to_text=template.get_reply_to_text() ) provider_tasks.deliver_sms.apply_async( [str(saved_notification.id)], queue=QueueNames.SEND_SMS if not service.research_mode else QueueNames.RESEARCH_MODE ) current_app.logger.debug( "SMS {} created at {} for job {}".format( saved_notification.id, saved_notification.created_at, notification.get('job', None)) ) except SQLAlchemyError as e: handle_exception(self, notification, notification_id, e)
def update_user_attribute(user_id): user_to_update = get_user_by_id(user_id=user_id) req_json = request.get_json() if 'updated_by' in req_json: updated_by = get_user_by_id(user_id=req_json.pop('updated_by')) else: updated_by = None update_dct, errors = user_update_schema_load_json.load(req_json) if errors: raise InvalidRequest(errors, status_code=400) save_user_attribute(user_to_update, update_dict=update_dct) if updated_by: if 'email_address' in update_dct: template = dao_get_template_by_id( current_app.config['TEAM_MEMBER_EDIT_EMAIL_TEMPLATE_ID']) recipient = user_to_update.email_address reply_to = template.service.get_default_reply_to_email_address() elif 'mobile_number' in update_dct: template = dao_get_template_by_id( current_app.config['TEAM_MEMBER_EDIT_MOBILE_TEMPLATE_ID']) recipient = user_to_update.mobile_number reply_to = template.service.get_default_sms_sender() else: return jsonify(data=user_to_update.serialize()), 200 service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID']) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=recipient, service=service, personalisation={ 'name': user_to_update.name, 'servicemanagername': updated_by.name, 'email address': user_to_update.email_address }, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=reply_to) send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY) return jsonify(data=user_to_update.serialize()), 200
def save_sms(self, service_id, notification_id, encrypted_notification, sender_id=None): notification = encryption.decrypt(encrypted_notification) service = dao_fetch_service_by_id(service_id) template = dao_get_template_by_id(notification['template'], version=notification['template_version']) if sender_id: reply_to_text = dao_get_service_sms_senders_by_id( service_id, sender_id).sms_sender else: reply_to_text = template.get_reply_to_text() if not service_allowed_to_send_to(notification['to'], service, KEY_TYPE_NORMAL): current_app.logger.debug( "SMS {} failed as restricted service".format(notification_id)) return try: saved_notification = persist_notification( template_id=notification['template'], template_version=notification['template_version'], recipient=notification['to'], service=service, personalisation=notification.get('personalisation'), notification_type=SMS_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, created_at=datetime.utcnow(), job_id=notification.get('job', None), job_row_number=notification.get('row_number', None), notification_id=notification_id, reply_to_text=reply_to_text) send_notification_to_queue(saved_notification, service.research_mode) current_app.logger.debug("SMS {} created at {} for job {}".format( saved_notification.id, saved_notification.created_at, notification.get('job', None))) except SQLAlchemyError as e: handle_exception(self, notification, notification_id, e)
def test_exception_thown_by_redis_store_get_should_not_be_fatal(sample_template, sample_api_key, mocker): mocker.patch( 'app.notifications.process_notifications.redis_store.redis_store.incr', side_effect=Exception("broken redis")) notification = persist_notification( sample_template.id, sample_template.version, '+447111111111', sample_template.service.id, {}, 'sms', sample_api_key.id, sample_api_key.key_type) assert Notification.query.count() == 1 assert Notification.query.get(notification.id) is not None assert NotificationHistory.query.count() == 1
def send_notification_to_notify_support(template_id, personalisation=None): personalisation = personalisation or {} template = dao_get_template_by_id(template_id) notify_service = dao_fetch_service_by_id(current_app.config['NOTIFY_SERVICE_ID']) validate_template(template.id, personalisation, notify_service, template.template_type) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=current_app.config['NOTIFY_SUPPORT_EMAIL'], service=notify_service, personalisation=personalisation, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=notify_service.get_default_reply_to_email_address() ) send_notification_to_queue(notification, False, queue=QueueNames.NOTIFY)
def test_persist_notification_should_not_persist_recipient_identifier_if_none_present_or_toggle_off( notify_db, recipient_identifiers_enabled, recipient_identifier, sample_job, sample_api_key, mocker): mocker.patch( 'app.notifications.process_notifications.accept_recipient_identifiers_enabled', return_value=recipient_identifiers_enabled) notification = persist_notification( template_id=sample_job.template.id, template_version=sample_job.template.version, service=sample_job.service, personalisation=None, notification_type='email', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, job_id=sample_job.id, recipient_identifier=recipient_identifier) assert RecipientIdentifier.query.count() == 0 assert notification.recipient_identifiers == {}
def verify_reply_to_email_address(service_id): email_address, errors = email_data_request_schema.load(request.get_json()) check_if_reply_to_address_already_in_use(service_id, email_address["email"]) template = dao_get_template_by_id(current_app.config['REPLY_TO_EMAIL_ADDRESS_VERIFICATION_TEMPLATE_ID']) notify_service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID']) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=email_address["email"], service=notify_service, personalisation='', notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=notify_service.get_default_reply_to_email_address() ) send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY) return jsonify(data={"id": saved_notification.id}), 201
def test_persist_notification_creates_and_save_to_db(sample_template, sample_api_key, sample_job): assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 0 notification = persist_notification( template_id=sample_template.id, template_version=sample_template.version, recipient='+447111111111', service=sample_template.service, personalisation={}, notification_type='sms', api_key_id=sample_api_key.id, key_type=sample_api_key.key_type, job_id=sample_job.id, job_row_number=100, reference="ref", reply_to_text=sample_template.service.get_default_sms_sender()) assert Notification.query.get(notification.id) is not None notification_from_db = Notification.query.one() assert notification_from_db.id == notification.id assert notification_from_db.template_id == notification.template_id assert notification_from_db.template_version == notification.template_version assert notification_from_db.api_key_id == notification.api_key_id assert notification_from_db.key_type == notification.key_type assert notification_from_db.key_type == notification.key_type assert notification_from_db.billable_units == notification.billable_units assert notification_from_db.notification_type == notification.notification_type assert notification_from_db.created_at == notification.created_at assert not notification_from_db.sent_at assert notification_from_db.updated_at == notification.updated_at assert notification_from_db.status == notification.status assert notification_from_db.reference == notification.reference assert notification_from_db.client_reference == notification.client_reference assert notification_from_db.created_by_id == notification.created_by_id assert notification_from_db.reply_to_text == sample_template.service.get_default_sms_sender( )
def invite_user_to_org(organisation_id): data = request.get_json() validate(data, post_create_invited_org_user_status_schema) invited_org_user = InvitedOrganisationUser( email_address=data["email_address"], invited_by_id=data["invited_by"], organisation_id=organisation_id, ) save_invited_org_user(invited_org_user) template = dao_get_template_by_id( current_app.config["ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID"]) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=invited_org_user.email_address, service=template.service, personalisation={ "user_name": invited_org_user.invited_by.name, "organisation_name": invited_org_user.organisation.name, "url": invited_org_user_url( invited_org_user.id, data.get("invite_link_host"), ), }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=invited_org_user.invited_by.email_address, ) send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY) return jsonify(data=invited_org_user.serialize()), 201
def invite_user_to_org(organisation_id): data = request.get_json() validate(data, post_create_invited_org_user_status_schema) invited_org_user = InvitedOrganisationUser( email_address=data['email_address'], invited_by_id=data['invited_by'], organisation_id=organisation_id) save_invited_org_user(invited_org_user) template = dao_get_template_by_id( current_app.config['ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID']) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=invited_org_user.email_address, service=template.service, personalisation={ 'user_name': ('The Catalyst Notify team' if invited_org_user.invited_by.platform_admin else invited_org_user.invited_by.name), 'organisation_name': invited_org_user.organisation.name, 'url': invited_org_user_url( invited_org_user.id, data.get('invite_link_host'), ), }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=invited_org_user.invited_by.email_address) send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY) return jsonify(data=invited_org_user.serialize()), 201
def create_invited_user(service_id): request_json = request.get_json() invited_user, errors = invited_user_schema.load(request_json) save_invited_user(invited_user) if invited_user.service.has_permission(BROADCAST_TYPE): template_id = current_app.config[ 'BROADCAST_INVITATION_EMAIL_TEMPLATE_ID'] else: template_id = current_app.config['INVITATION_EMAIL_TEMPLATE_ID'] template = dao_get_template_by_id(template_id) service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID']) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=invited_user.email_address, service=service, personalisation={ 'user_name': invited_user.from_user.name, 'service_name': invited_user.service.name, 'url': invited_user_url( invited_user.id, request_json.get('invite_link_host'), ), }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reply_to_text=invited_user.from_user.email_address) send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY) return jsonify(data=invited_user_schema.dump(invited_user).data), 201
def send_user_email_verification(user_id): user_to_send_to = get_user_by_id(user_id=user_id) secret_code = create_secret_code() create_user_code(user_to_send_to, secret_code, 'email') template = dao_get_template_by_id(current_app.config['EMAIL_VERIFY_CODE_TEMPLATE_ID']) saved_notification = persist_notification( template_id=template.id, template_version=template.version, recipient=user_to_send_to.email_address, service_id=current_app.config['NOTIFY_SERVICE_ID'], personalisation={ 'name': user_to_send_to.name, 'url': _create_verification_url(user_to_send_to, secret_code) }, notification_type=EMAIL_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL ) send_notification_to_queue(saved_notification, False, queue="notify") return jsonify({}), 204