diff --git a/app/main/forms.py b/app/main/forms.py
index ca5e9f1ba..47e695ca8 100644
--- a/app/main/forms.py
+++ b/app/main/forms.py
@@ -717,15 +717,38 @@ class ServiceInboundNumberForm(Form):
)
-class ServiceInboundApiForm(Form):
- url = StringField("Callback URL",
- validators=[DataRequired(message='Can’t be empty'),
- Regexp(regex="^https.*",
- message='Must be a valid https URL')]
- )
- bearer_token = PasswordFieldShowHasContent("Bearer token",
- validators=[DataRequired(message='Can’t be empty'),
- Length(min=10, message='Must be at least 10 characters')])
+class ServiceCallbacksForm(Form):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.can_receive_inbound = kwargs['can_receive_inbound']
+
+ inbound_url = StringField("Inbound URL")
+ inbound_bearer_token = PasswordFieldShowHasContent("Bearer token")
+ outbound_url = StringField(
+ "Outbound URL",
+ validators=[DataRequired(message='Can’t be empty'),
+ Regexp(regex="^https.*", message='Must be a valid https URL')]
+ )
+ outbound_bearer_token = PasswordFieldShowHasContent(
+ "Bearer token",
+ validators=[DataRequired(message='Can’t be empty'),
+ Length(min=10, message='Must be at least 10 characters')]
+ )
+
+ def validate_inbound_url(self, field):
+ pattern = re.compile("^https.*")
+ if self.can_receive_inbound:
+ if not field.data:
+ raise ValidationError('Can’t be empty')
+ elif not pattern.match(field.data):
+ raise ValidationError('Must be a valid https URL')
+
+ def validate_inbound_bearer_token(self, field):
+ if self.can_receive_inbound:
+ if not field.data:
+ raise ValidationError('Can’t be empty')
+ elif len(field.data) < 10:
+ raise ValidationError('Must be at least 10 characters')
class InternationalSMSForm(Form):
diff --git a/app/main/views/api_keys.py b/app/main/views/api_keys.py
index 14d31bb65..98e886ca6 100644
--- a/app/main/views/api_keys.py
+++ b/app/main/views/api_keys.py
@@ -1,11 +1,13 @@
from flask import request, render_template, redirect, url_for, flash, Markup, abort
-from flask_login import login_required
+from flask_login import login_required, current_user
from app.main import main
-from app.main.forms import CreateKeyForm, Whitelist
+from app.main.forms import CreateKeyForm, Whitelist, ServiceCallbacksForm
from app import api_key_api_client, service_api_client, notification_api_client, current_service
from app.utils import user_has_permissions, email_safe
from app.notify_client.api_key_api_client import KEY_TYPE_NORMAL, KEY_TYPE_TEST, KEY_TYPE_TEAM
+dummy_bearer_token = 'bearer_token_set'
+
@main.route("/services//api")
@login_required
@@ -113,3 +115,87 @@ def revoke_api_key(service_id, key_id):
api_key_api_client.revoke_api_key(service_id=service_id, key_id=key_id)
flash('‘{}’ was revoked'.format(key_name), 'default_with_tick')
return redirect(url_for('.api_keys', service_id=service_id))
+
+
+def get_apis():
+ callback_api = None
+ inbound_api = None
+ if current_service['service_callback_api']:
+ callback_api = service_api_client.get_service_callback_api(
+ current_service['id'],
+ current_service.get('service_callback_api')[0]
+ )
+ if current_service['inbound_api']:
+ inbound_api = service_api_client.get_service_inbound_api(
+ current_service['id'],
+ current_service.get('inbound_api')[0]
+ )
+
+ return (callback_api, inbound_api)
+
+
+def check_token_against_dummy_bearer(token):
+ if token != dummy_bearer_token:
+ return token
+ else:
+ return ''
+
+
+@main.route("/services//api/callbacks", methods=['GET', 'POST'])
+@login_required
+def api_callbacks(service_id):
+ callback_api, inbound_api = get_apis()
+ can_receive_inbound = 'inbound_sms' in current_service['permissions']
+
+ form = ServiceCallbacksForm(
+ inbound_url=inbound_api.get('url') if inbound_api else '',
+ inbound_bearer_token=dummy_bearer_token if inbound_api else '',
+ outbound_url=callback_api.get('url') if callback_api else '',
+ outbound_bearer_token=dummy_bearer_token if callback_api else '',
+ can_receive_inbound=can_receive_inbound,
+ )
+
+ if form.validate_on_submit():
+ if callback_api:
+ if (callback_api.get('url') != form.outbound_url.data
+ or form.outbound_bearer_token.data != dummy_bearer_token):
+ service_api_client.update_service_callback_api(
+ service_id,
+ url=form.outbound_url.data,
+ bearer_token=check_token_against_dummy_bearer(form.outbound_bearer_token.data),
+ user_id=current_user.id,
+ callback_api_id=callback_api.get('id')
+ )
+ else:
+ service_api_client.create_service_callback_api(
+ service_id,
+ url=form.outbound_url.data,
+ bearer_token=form.outbound_bearer_token.data,
+ user_id=current_user.id
+ )
+ if can_receive_inbound:
+ if inbound_api:
+ if (inbound_api.get('url') != form.inbound_url.data
+ or form.inbound_bearer_token.data != dummy_bearer_token):
+ service_api_client.update_service_inbound_api(
+ service_id,
+ url=form.inbound_url.data,
+ bearer_token=check_token_against_dummy_bearer(form.inbound_bearer_token.data),
+ user_id=current_user.id,
+ inbound_api_id=inbound_api.get('id')
+ )
+ else:
+ service_api_client.create_service_inbound_api(
+ service_id,
+ url=form.inbound_url.data,
+ bearer_token=form.inbound_bearer_token.data,
+ user_id=current_user.id
+ )
+
+ return redirect(url_for('.api_integration', service_id=service_id))
+
+ return render_template(
+ 'views/api/callbacks.html',
+ form=form,
+ can_receive_inbound=can_receive_inbound,
+ )
diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py
index 80bb9d4e9..7631b0f39 100644
--- a/app/main/views/service_settings.py
+++ b/app/main/views/service_settings.py
@@ -1,5 +1,3 @@
-from urllib.parse import urlparse
-
import requests
from flask import (
render_template,
@@ -33,7 +31,6 @@ from app.main.forms import (
ServiceLetterContactBlockForm,
ServiceBrandingOrg,
LetterBranding,
- ServiceInboundApiForm,
InternationalSMSForm,
OrganisationTypeForm,
FreeSMSAllowance,
@@ -44,17 +41,6 @@ from app import user_api_client, current_service, organisations_client, inbound_
from notifications_utils.formatters import formatted_list
-dummy_bearer_token = 'bearer_token_set'
-
-
-def get_inbound_api():
- if current_service['inbound_api']:
- return service_api_client.get_service_inbound_api(
- current_service['id'],
- current_service.get('inbound_api')[0]
- )
-
-
@main.route("/services//service-settings")
@login_required
@user_has_permissions('manage_settings', admin_override=True)
@@ -65,14 +51,6 @@ def service_settings(service_id):
else:
organisation = None
- inbound_api = get_inbound_api()
- if inbound_api:
- parsed_url = urlparse(inbound_api.get('url')) if inbound_api else ''
- inbound_api_url = '{uri.scheme}://{uri.netloc}{elide_token}'.format(
- uri=parsed_url, elide_token='...' if parsed_url.path else '')
- else:
- inbound_api_url = ''
-
inbound_number = inbound_number_client.get_inbound_sms_number_for_service(service_id)
disp_inbound_number = inbound_number['data'].get('number', '')
reply_to_email_addresses = service_api_client.get_reply_to_email_addresses(service_id)
@@ -100,7 +78,6 @@ def service_settings(service_id):
current_service.get('dvla_organisation', '001')
),
can_receive_inbound=('inbound_sms' in current_service['permissions']),
- inbound_api_url=inbound_api_url,
inbound_number=disp_inbound_number,
default_reply_to_email_address=default_reply_to_email_address,
reply_to_email_address_count=reply_to_email_address_count,
@@ -807,41 +784,3 @@ def get_branding_as_dict(organisations):
'colour': organisation['colour']
} for organisation in organisations
}
-
-
-@main.route("/services//service-settings/set-inbound-api", methods=['GET', 'POST'])
-@login_required
-@user_has_permissions('manage_settings', admin_override=True)
-def service_set_inbound_api(service_id):
- if 'inbound_sms' not in current_service['permissions']:
- abort(403)
-
- inbound_api = get_inbound_api()
- form = ServiceInboundApiForm(
- url=inbound_api.get('url') if inbound_api else '',
- bearer_token=dummy_bearer_token if inbound_api else ''
- )
-
- if form.validate_on_submit():
- if inbound_api:
- if inbound_api.get('url') != form.url.data or form.bearer_token.data != dummy_bearer_token:
- service_api_client.update_service_inbound_api(
- service_id,
- url=form.url.data,
- bearer_token=form.bearer_token.data if form.bearer_token.data != dummy_bearer_token else '',
- user_id=current_user.id,
- inbound_api_id=inbound_api.get('id')
- )
- else:
- service_api_client.create_service_inbound_api(
- service_id,
- url=form.url.data,
- bearer_token=form.bearer_token.data,
- user_id=current_user.id
- )
- return redirect(url_for('.service_settings', service_id=service_id))
-
- return render_template(
- 'views/service-settings/set-inbound-api.html',
- form=form,
- )
diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py
index 08f78c038..2b7b6ead4 100644
--- a/app/notify_client/service_api_client.py
+++ b/app/notify_client/service_api_client.py
@@ -387,6 +387,30 @@ class ServiceAPIClient(NotifyAdminAPIClient):
}
)
+ def get_service_callback_api(self, service_id, callback_api_id):
+ return self.get(
+ "/service/{}/delivery-receipt-api/{}".format(
+ service_id, callback_api_id
+ )
+ )['data']
+
+ def update_service_callback_api(self, service_id, url, bearer_token, user_id, callback_api_id):
+ data = {
+ "url": url,
+ "updated_by_id": user_id
+ }
+ if bearer_token:
+ data['bearer_token'] = bearer_token
+ return self.post("/service/{}/delivery-receipt-api/{}".format(service_id, callback_api_id), data)
+
+ def create_service_callback_api(self, service_id, url, bearer_token, user_id):
+ data = {
+ "url": url,
+ "bearer_token": bearer_token,
+ "updated_by_id": user_id
+ }
+ return self.post("/service/{}/delivery-receipt-api".format(service_id), data)
+
class ServicesBrowsableItem(BrowsableItem):
@property
diff --git a/app/templates/views/service-settings/set-inbound-api.html b/app/templates/views/api/callbacks.html
similarity index 53%
rename from app/templates/views/service-settings/set-inbound-api.html
rename to app/templates/views/api/callbacks.html
index 9530b36d5..4747e510d 100644
--- a/app/templates/views/service-settings/set-inbound-api.html
+++ b/app/templates/views/api/callbacks.html
@@ -3,33 +3,44 @@
{% from "components/page-footer.html" import page_footer %}
{% block service_page_title %}
- Callback URL
+ Callbacks
{% endblock %}
{% block maincolumn_content %}
diff --git a/app/templates/views/api/index.html b/app/templates/views/api/index.html
index 1b99ff3e1..4ef0ea2cf 100644
--- a/app/templates/views/api/index.html
+++ b/app/templates/views/api/index.html
@@ -21,7 +21,7 @@
Whitelist
diff --git a/app/templates/views/callbacks.html b/app/templates/views/callbacks.html
index 643153911..b61a58755 100644
--- a/app/templates/views/callbacks.html
+++ b/app/templates/views/callbacks.html
@@ -31,12 +31,14 @@
If you don’t have ‘receive text messages’ enabled for your service, get in touch and we can turn it on for you.
- Format of the callback
+ Format of the callbacks
The format of the callback message you receive is JSON.
+ Received text messages callback
+
{% call mapping_table(
caption='Callback message format',
@@ -60,4 +62,32 @@
{% endcall %}
+ Status callback
+
+
+ {% call mapping_table(
+ caption='Callback message format',
+ field_headings=['Key', 'Description', 'Format'],
+ field_headings_visible=True,
+ caption_visible=False
+ ) %}
+ {% for key, description, format in [
+ ('id', 'Notify’s id for the status receipts', 'UUID'),
+ ('reference', 'The reference sent by the service', '12345678'),
+ ('to', 'The email address of the recipient', 'hello@gov.uk'),
+ ('status', 'The status of the notification', 'delivered | permanent-failure | temporary-failure | technical-failure'),
+ ('created_at', 'The time the service sent the request', '2017-05-14T12:15:30.000000Z'),
+ ('updated_at', 'The last time the status was updated', '2017-05-14T12:15:30.000000Z'),
+ ('sent_at', 'The time the notification was sent', '2017-05-14T12:15:30.000000Z or nil'),
+ ('notification_type', 'The notification type', 'email | sms | letter')
+ ] %}
+ {% call row() %}
+ {% call row_heading() %} {{ key }} {% endcall %}
+ {{ text_field(description) }}
+ {{ text_field(format) }}
+ {% endcall %}
+ {% endfor %}
+ {% endcall %}
+
+
{% endblock %}
diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html
index c4bbb8d6e..51bf2750c 100644
--- a/app/templates/views/service-settings.html
+++ b/app/templates/views/service-settings.html
@@ -120,14 +120,6 @@
{{ edit_field('Change', url_for('.service_set_inbound_sms', service_id=current_service.id)) }}
{% endcall %}
- {% if can_receive_inbound %}
- {% call row() %}
- {{ text_field('Callback URL for received text messages') }}
- {{ optional_text_field(inbound_api_url) }}
- {{ edit_field('Change', url_for('.service_set_inbound_api', service_id=current_service.id)) }}
- {% endcall %}
- {% endif %}
-
{% endif %}
{% endcall %}
diff --git a/tests/__init__.py b/tests/__init__.py
index 372d34f6c..262b008e5 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -53,6 +53,7 @@ def service_json(
created_at=None,
letter_contact_block=None,
inbound_api=None,
+ service_callback_api=None,
permissions=None,
organisation_type='central',
free_sms_fragment_limit=250000,
@@ -84,6 +85,7 @@ def service_json(
'dvla_organisation': '001',
'permissions': permissions,
'inbound_api': inbound_api,
+ 'service_callback_api': service_callback_api,
'prefix_sms': prefix_sms,
}
diff --git a/tests/app/main/views/test_api_keys.py b/tests/app/main/views/test_api_keys.py
index 412e9cc69..dc1ba9c00 100644
--- a/tests/app/main/views/test_api_keys.py
+++ b/tests/app/main/views/test_api_keys.py
@@ -391,3 +391,267 @@ def test_should_validate_whitelist_items(
assert jump_links[1]['href'] == '#phone_numbers'
mock_update_whitelist.assert_not_called()
+
+
+@pytest.mark.parametrize('url, bearer_token, expected_errors', [
+ ("", "", "Can’t be empty Can’t be empty"),
+ ("http://not_https.com", "1234567890", "Must be a valid https URL"),
+ ("https://test.com", "123456789", "Must be at least 10 characters"),
+])
+def test_set_outbound_api_validation(
+ client_request,
+ service_one,
+ url,
+ bearer_token,
+ expected_errors,
+ mock_create_service_callback_api,
+ mock_update_service_callback_api
+):
+ response = client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data={"outbound_url": url, "outbound_bearer_token": bearer_token},
+ _expected_status=200
+ )
+ error_msgs = ' '.join(msg.text.strip() for msg in response.select(".error-message"))
+
+ assert error_msgs == expected_errors
+ mock_create_service_callback_api.assert_not_called()
+ mock_update_service_callback_api.assert_not_called()
+
+
+@pytest.mark.parametrize('url, bearer_token, expected_errors', [
+ ("", "", "Can’t be empty Can’t be empty Can’t be empty Can’t be empty"),
+ ("http://not_https.com", "1234567890", "Must be a valid https URL Must be a valid https URL"),
+ ("https://test.com", "123456789", "Must be at least 10 characters Must be at least 10 characters"),
+])
+def test_set_inbound_api_validation(
+ client_request,
+ service_one,
+ url,
+ bearer_token,
+ expected_errors,
+ fake_uuid
+):
+ service_one['permissions'] = ['inbound_sms']
+
+ data = {
+ "inbound_url": url,
+ "inbound_bearer_token": bearer_token,
+ "outbound_url": url,
+ "outbound_bearer_token": bearer_token
+ }
+
+ response = client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=data,
+ _expected_status=200
+ )
+ error_msgs = ' '.join(msg.text.strip() for msg in response.select(".error-message"))
+
+ assert error_msgs == expected_errors
+
+
+def test_create_new_callback_api_without_inbound_set(
+ client_request,
+ service_one,
+ mock_create_service_callback_api,
+ mock_get_notifications,
+ fake_uuid,
+ mocker,
+):
+ service_one['service_callback_api'] = []
+
+ callback_api_data = {
+ 'outbound_url': "https://test.url.com/",
+ 'outbound_bearer_token': '1234567890',
+ 'user_id': fake_uuid
+ }
+
+ client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=callback_api_data,
+ _follow_redirects=True,
+ )
+
+ callback_api_data['updated_by_id'] = service_one['users'][0]
+
+ mock_create_service_callback_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test.url.com/",
+ bearer_token="1234567890",
+ user_id=fake_uuid
+ )
+
+
+def test_update_new_callback_api_without_inbound_set(
+ client_request,
+ service_one,
+ mock_get_valid_service_callback_api,
+ mock_update_service_callback_api,
+ mock_get_notifications,
+ fake_uuid,
+ mocker,
+):
+ service_one['service_callback_api'] = [fake_uuid]
+
+ callback_api_data = {
+ 'outbound_url': "https://test.url.com/",
+ 'outbound_bearer_token': '1234567890',
+ 'user_id': fake_uuid
+ }
+
+ client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=callback_api_data,
+ _follow_redirects=True,
+ )
+
+ callback_api_data['updated_by_id'] = service_one['users'][0]
+
+ mock_update_service_callback_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test.url.com/",
+ bearer_token="1234567890",
+ user_id=fake_uuid,
+ callback_api_id=fake_uuid
+ )
+
+
+def test_inbound_fields_do_not_show_if_inbound_is_disabled(
+ client_request,
+ service_one,
+ mocker
+):
+ response = client_request.get(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _expected_status=200
+ )
+ assert response.select_one('label[for="inbound_url"]') is None
+ assert response.select_one('label[for="inbound_bearer_token"]') is None
+
+
+def test_create_inbound_and_outbound_apis(
+ client_request,
+ service_one,
+ mocker,
+ mock_create_service_callback_api,
+ mock_create_service_inbound_api,
+ mock_get_notifications,
+ fake_uuid,
+):
+ service_one['permissions'] = ['inbound_sms']
+
+ callback_api_data = {
+ 'outbound_url': "https://test.url.com/",
+ 'outbound_bearer_token': '1234567890',
+ 'inbound_url': "https://test2.url.com/",
+ 'inbound_bearer_token': '5678901234',
+ 'user_id': fake_uuid
+ }
+
+ client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=callback_api_data,
+ _follow_redirects=True,
+ )
+
+ mock_create_service_callback_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test.url.com/",
+ bearer_token="1234567890",
+ user_id=fake_uuid
+ )
+
+ mock_create_service_inbound_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test2.url.com/",
+ bearer_token="5678901234",
+ user_id=fake_uuid
+ )
+
+
+def test_update_inbound_and_outbound_apis(
+ client_request,
+ service_one,
+ mocker,
+ mock_get_valid_service_callback_api,
+ mock_get_valid_service_inbound_api,
+ mock_update_service_callback_api,
+ mock_update_service_inbound_api,
+ mock_get_notifications,
+ fake_uuid,
+):
+ service_one['service_callback_api'] = [fake_uuid]
+ service_one['inbound_api'] = [fake_uuid]
+ service_one['permissions'] = ['inbound_sms']
+
+ callback_api_data = {
+ 'outbound_url': "https://test.url.com/",
+ 'outbound_bearer_token': '1234567890',
+ 'inbound_url': "https://test2.url.com/",
+ 'inbound_bearer_token': '5678901234',
+ 'user_id': fake_uuid
+ }
+
+ client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=callback_api_data,
+ _follow_redirects=True,
+ )
+
+ mock_update_service_callback_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test.url.com/",
+ bearer_token="1234567890",
+ user_id=fake_uuid,
+ callback_api_id=fake_uuid
+ )
+
+ mock_update_service_inbound_api.assert_called_once_with(
+ service_one['id'],
+ url="https://test2.url.com/",
+ bearer_token="5678901234",
+ user_id=fake_uuid,
+ inbound_api_id=fake_uuid
+ )
+
+
+def test_save_callback_apis_without_changes_does_not_update_callback_apis(
+ client_request,
+ service_one,
+ mocker,
+ mock_get_valid_service_callback_api,
+ mock_get_valid_service_inbound_api,
+ mock_update_service_callback_api,
+ mock_update_service_inbound_api,
+ mock_get_notifications,
+ fake_uuid,
+):
+ service_one['service_callback_api'] = [fake_uuid]
+ service_one['inbound_api'] = [fake_uuid]
+ service_one['permissions'] = ['inbound_sms']
+
+ callback_api_data = {
+ 'outbound_url': "https://hello2.gov.uk",
+ 'outbound_bearer_token': 'bearer_token_set',
+ 'inbound_url': "https://hello3.gov.uk",
+ 'inbound_bearer_token': 'bearer_token_set',
+ 'user_id': fake_uuid
+ }
+
+ client_request.post(
+ 'main.api_callbacks',
+ service_id=service_one['id'],
+ _data=callback_api_data,
+ _follow_redirects=True,
+ )
+
+ assert mock_update_service_callback_api.called is False
+ assert mock_update_service_inbound_api.called is False
diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py
index 9f79cfb8d..02d22db84 100644
--- a/tests/app/main/views/test_service_settings.py
+++ b/tests/app/main/views/test_service_settings.py
@@ -7,7 +7,6 @@ from flask import url_for
from werkzeug.exceptions import InternalServerError
import app
-from app.main.views.service_settings import dummy_bearer_token
from app.utils import email_safe
from tests import validate_route_permission, service_json
from tests.conftest import (
@@ -136,7 +135,6 @@ def test_should_show_overview(
'Text messages start with service name On Change',
'International text messages On Change',
'Receive text messages On Change',
- 'Callback URL for received text messages Not set Change',
'Label Value Action',
'Send letters Off Change',
@@ -186,47 +184,6 @@ def test_should_show_overview_for_service_with_more_things_set(
assert row == " ".join(page.find_all('tr')[index + 1].text.split())
-@pytest.mark.parametrize('url, elided_url', [
- ('https://test.url.com/inbound', 'https://test.url.com...'),
- ('https://test.url.com/', 'https://test.url.com...'),
- ('https://test.url.com', 'https://test.url.com'),
-])
-def test_service_settings_show_elided_api_url_if_needed(
- logged_in_platform_admin_client,
- service_one,
- single_reply_to_email_address,
- single_sms_sender,
- single_letter_contact_block,
- mocker,
- fake_uuid,
- url,
- elided_url,
- mock_get_service_settings_page_common,
-):
- service_one['permissions'] = ['sms', 'email', 'inbound_sms']
- service_one['inbound_api'] = [fake_uuid]
-
- mocked_get_fn = mocker.patch(
- 'app.service_api_client.get',
- return_value={'data': {'id': fake_uuid, 'url': url}}
- )
-
- response = logged_in_platform_admin_client.get(
- url_for(
- 'main.service_settings',
- service_id=service_one['id']
- )
- )
- assert response.status_code == 200
- page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
-
- non_empty_trs = [tr.find_all('td') for tr in page.find_all('tr') if tr.find_all('td')]
- api_url = [api_setting[1].text.strip() for api_setting in non_empty_trs
- if api_setting[0].text.strip() == 'Callback URL for received text messages'][0]
- assert api_url == elided_url
- assert mocked_get_fn.called is True
-
-
def test_if_cant_send_letters_then_cant_see_letter_contact_block(
logged_in_client,
service_one,
@@ -1274,34 +1231,6 @@ def test_does_not_show_research_mode_indicator(
assert not element
-@pytest.mark.parametrize('url, bearer_token, expected_errors', [
- ("", "", "Can’t be empty Can’t be empty"),
- ("http://not_https.com", "1234567890", "Must be a valid https URL"),
- ("https://test.com", "123456789", "Must be at least 10 characters"),
-])
-def test_set_inbound_api_validation(
- logged_in_client,
- mock_update_service,
- service_one,
- mock_get_letter_organisations,
- url,
- bearer_token,
- expected_errors,
-):
- service_one['permissions'] = ['inbound_sms']
- response = logged_in_client.post(url_for(
- 'main.service_set_inbound_api',
- service_id=service_one['id']),
- data={"url": url, "bearer_token": bearer_token}
- )
- page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
- error_msgs = ' '.join(msg.text.strip() for msg in page.select(".error-message"))
-
- assert response.status_code == 200
- assert error_msgs == expected_errors
- assert not mock_update_service.called
-
-
@pytest.mark.parametrize('method', ['get', 'post'])
def test_cant_set_letter_contact_block_if_service_cant_send_letters(
logged_in_client,
@@ -1707,113 +1636,6 @@ def test_switch_service_enable_international_sms(
assert mocked_fn.call_args[0][0] == service_one['id']
-def test_set_new_inbound_api_and_valid_bearer_token_calls_create_inbound_api_endpoint(
- logged_in_platform_admin_client,
- service_one,
- mocker,
-):
- service_one['permissions'] = ['inbound_sms']
- service_one['inbound_api'] = []
-
- mocked_post_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
-
- inbound_api_data = {'url': "https://test.url.com/", 'bearer_token': '1234567890'}
- response = logged_in_platform_admin_client.post(
- url_for(
- 'main.service_set_inbound_api',
- service_id=service_one['id']
- ),
- data=inbound_api_data
- )
- assert response.status_code == 302
- assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
- assert mocked_post_fn.called
-
- inbound_api_data['updated_by_id'] = service_one['users'][0]
- assert mocked_post_fn.call_args == call("/service/{}/inbound-api".format(service_one['id']), inbound_api_data)
-
-
-@pytest.mark.parametrize(
- 'inbound_api_data', [
- {'url': "https://test.url.com/inbound", 'bearer_token': dummy_bearer_token},
- {'url': "https://test.url.com/inbound", 'bearer_token': '1234567890'},
- {'url': "https://test.url.com/", 'bearer_token': 'new_1234567890'},
- ]
-)
-def test_update_inbound_api_and_valid_bearer_token_calls_update_inbound_api_endpoint(
- logged_in_platform_admin_client,
- service_one,
- mocker,
- fake_uuid,
- inbound_api_data,
-):
- service_one['permissions'] = ['inbound_sms']
- service_one['inbound_api'] = [fake_uuid]
-
- initial_api_data = {'data': {'id': fake_uuid, 'url': "https://test.url.com/"}}
-
- mocked_get_fn = mocker.patch('app.service_api_client.get', return_value=initial_api_data)
- mocked_post_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
-
- response = logged_in_platform_admin_client.get(
- url_for(
- 'main.service_set_inbound_api',
- service_id=service_one['id']
- )
- )
- page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
-
- assert page.find('input', {'id': 'url'}).get('value') == initial_api_data['data']['url']
- assert page.find('input', {'id': 'bearer_token'}).get('value') == dummy_bearer_token
-
- response = logged_in_platform_admin_client.post(
- url_for(
- 'main.service_set_inbound_api',
- service_id=service_one['id']
- ),
- data=inbound_api_data
- )
- assert response.status_code == 302
- assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
- assert mocked_get_fn.called is True
- assert mocked_post_fn.called is True
-
- if inbound_api_data['bearer_token'] == dummy_bearer_token:
- del inbound_api_data['bearer_token']
- inbound_api_data['updated_by_id'] = service_one['users'][0]
-
- assert mocked_post_fn.call_args == call(
- "/service/{}/inbound-api/{}".format(service_one['id'], fake_uuid), inbound_api_data)
-
-
-def test_save_inbound_api_without_changes_does_not_update_inbound_api(
- logged_in_platform_admin_client,
- service_one,
- mocker,
- fake_uuid,
-):
- service_one['permissions'] = ['inbound_sms']
- service_one['inbound_api'] = [fake_uuid]
-
- initial_api_data = {'data': {'id': fake_uuid, 'url': "https://test.url.com/"}}
- inbound_api_data = {'url': initial_api_data['data']['url'], 'bearer_token': dummy_bearer_token}
-
- mocked_get_fn = mocker.patch('app.service_api_client.get', return_value=initial_api_data)
- mocked_post_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
-
- response = logged_in_platform_admin_client.post(
- url_for(
- 'main.service_set_inbound_api',
- service_id=service_one['id']
- ),
- data=inbound_api_data
- )
- assert response.status_code == 302
- assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
- assert mocked_get_fn.called is True
- assert mocked_post_fn.called is False
-
-
def test_archive_service_after_confirm(
logged_in_platform_admin_client,
service_one,
diff --git a/tests/conftest.py b/tests/conftest.py
index 004e87052..88ed70fb8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2497,3 +2497,65 @@ def valid_token(app_, fake_uuid):
app_.config['SECRET_KEY'],
app_.config['DANGEROUS_SALT']
)
+
+
+@pytest.fixture(scope='function')
+def mock_get_valid_service_inbound_api(mocker):
+ def _get(service_id, inbound_api_id):
+ return {
+ 'created_at': '2017-12-04T10:52:55.289026Z',
+ 'updated_by_id': fake_uuid,
+ 'id': inbound_api_id,
+ 'url': 'https://hello3.gov.uk',
+ 'service_id': service_id,
+ 'updated_at': '2017-12-04T11:28:42.575153Z'
+ }
+
+ return mocker.patch('app.service_api_client.get_service_inbound_api', side_effect=_get)
+
+
+@pytest.fixture(scope='function')
+def mock_get_valid_service_callback_api(mocker):
+ def _get(service_id, callback_api_id):
+ return {
+ 'created_at': '2017-12-04T10:52:55.289026Z',
+ 'updated_by_id': fake_uuid,
+ 'id': callback_api_id,
+ 'url': 'https://hello2.gov.uk',
+ 'service_id': service_id,
+ 'updated_at': '2017-12-04T11:28:42.575153Z'
+ }
+
+ return mocker.patch('app.service_api_client.get_service_callback_api', side_effect=_get)
+
+
+@pytest.fixture(scope='function')
+def mock_create_service_inbound_api(mocker):
+ def _create_service_inbound_api(service_id, url, bearer_token, user_id):
+ return
+
+ return mocker.patch('app.service_api_client.create_service_inbound_api', side_effect=_create_service_inbound_api)
+
+
+@pytest.fixture(scope='function')
+def mock_update_service_inbound_api(mocker):
+ def _update_service_inbound_api(service_id, url, bearer_token, user_id, inbound_api_id):
+ return
+
+ return mocker.patch('app.service_api_client.update_service_inbound_api', side_effect=_update_service_inbound_api)
+
+
+@pytest.fixture(scope='function')
+def mock_create_service_callback_api(mocker):
+ def _create_service_callback_api(service_id, url, bearer_token, user_id):
+ return
+
+ return mocker.patch('app.service_api_client.create_service_callback_api', side_effect=_create_service_callback_api)
+
+
+@pytest.fixture(scope='function')
+def mock_update_service_callback_api(mocker):
+ def _update_service_callback_api(service_id, url, bearer_token, user_id, callback_api_id):
+ return
+
+ return mocker.patch('app.service_api_client.update_service_callback_api', side_effect=_update_service_callback_api)