mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-11 09:27:56 -04:00
Merge pull request #1447 from alphagov/vb-receipt-callback-dao
Email callback receipts rest end points
This commit is contained in:
@@ -82,6 +82,7 @@ def create_app(application):
|
||||
|
||||
def register_blueprint(application):
|
||||
from app.service.rest import service_blueprint
|
||||
from app.service.callback_rest import service_callback_blueprint
|
||||
from app.user.rest import user_blueprint
|
||||
from app.template.rest import template_blueprint
|
||||
from app.status.healthcheck import status as status_blueprint
|
||||
@@ -171,6 +172,9 @@ def register_blueprint(application):
|
||||
billing_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(billing_blueprint)
|
||||
|
||||
service_callback_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(service_callback_blueprint)
|
||||
|
||||
|
||||
def register_v2_blueprints(application):
|
||||
from app.v2.inbound_sms.get_inbound_sms import v2_inbound_sms_blueprint as get_inbound_sms
|
||||
|
||||
34
app/dao/service_callback_api_dao.py
Normal file
34
app/dao/service_callback_api_dao.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from datetime import datetime
|
||||
|
||||
from app import db, create_uuid
|
||||
from app.dao.dao_utils import transactional, version_class
|
||||
from app.models import ServiceCallbackApi
|
||||
|
||||
|
||||
@transactional
|
||||
@version_class(ServiceCallbackApi)
|
||||
def save_service_callback_api(service_callback_api):
|
||||
service_callback_api.id = create_uuid()
|
||||
service_callback_api.created_at = datetime.utcnow()
|
||||
db.session.add(service_callback_api)
|
||||
|
||||
|
||||
@transactional
|
||||
@version_class(ServiceCallbackApi)
|
||||
def reset_service_callback_api(service_callback_api, updated_by_id, url=None, bearer_token=None):
|
||||
if url:
|
||||
service_callback_api.url = url
|
||||
if bearer_token:
|
||||
service_callback_api.bearer_token = bearer_token
|
||||
service_callback_api.updated_by_id = updated_by_id
|
||||
service_callback_api.updated_at = datetime.utcnow()
|
||||
|
||||
db.session.add(service_callback_api)
|
||||
|
||||
|
||||
def get_service_callback_api(service_callback_api_id, service_id):
|
||||
return ServiceCallbackApi.query.filter_by(id=service_callback_api_id, service_id=service_id).first()
|
||||
|
||||
|
||||
def get_service_callback_api_for_service(service_id):
|
||||
return ServiceCallbackApi.query.filter_by(service_id=service_id).first()
|
||||
@@ -9,8 +9,7 @@ from app.models import ServiceInboundApi
|
||||
@version_class(ServiceInboundApi)
|
||||
def save_service_inbound_api(service_inbound_api):
|
||||
service_inbound_api.id = create_uuid()
|
||||
service_inbound_api.created_at == datetime.utcnow()
|
||||
service_inbound_api.bearer_token = service_inbound_api.bearer_token
|
||||
service_inbound_api.created_at = datetime.utcnow()
|
||||
db.session.add(service_inbound_api)
|
||||
|
||||
|
||||
|
||||
120
app/service/callback_rest.py
Normal file
120
app/service/callback_rest.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from flask import (
|
||||
Blueprint,
|
||||
jsonify,
|
||||
request,
|
||||
)
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app.errors import (
|
||||
register_errors
|
||||
)
|
||||
from app.models import (
|
||||
ServiceInboundApi,
|
||||
ServiceCallbackApi
|
||||
)
|
||||
from app.schema_validation import validate
|
||||
from app.service.service_callback_api_schema import (
|
||||
create_service_callback_api_schema,
|
||||
update_service_callback_api_schema
|
||||
)
|
||||
from app.dao.service_inbound_api_dao import (
|
||||
save_service_inbound_api,
|
||||
get_service_inbound_api,
|
||||
reset_service_inbound_api
|
||||
)
|
||||
from app.dao.service_callback_api_dao import (
|
||||
save_service_callback_api,
|
||||
get_service_callback_api,
|
||||
reset_service_callback_api
|
||||
)
|
||||
|
||||
service_callback_blueprint = Blueprint('service_callback', __name__, url_prefix='/service/<uuid:service_id>')
|
||||
|
||||
register_errors(service_callback_blueprint)
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/inbound-api', methods=['POST'])
|
||||
def create_service_inbound_api(service_id):
|
||||
data = request.get_json()
|
||||
validate(data, create_service_callback_api_schema)
|
||||
data["service_id"] = service_id
|
||||
inbound_api = ServiceInboundApi(**data)
|
||||
try:
|
||||
save_service_inbound_api(inbound_api)
|
||||
except SQLAlchemyError as e:
|
||||
return handle_sql_error(e, 'service_inbound_api')
|
||||
|
||||
return jsonify(data=inbound_api.serialize()), 201
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/inbound-api/<uuid:inbound_api_id>', methods=['POST'])
|
||||
def update_service_inbound_api(service_id, inbound_api_id):
|
||||
data = request.get_json()
|
||||
validate(data, update_service_callback_api_schema)
|
||||
|
||||
to_update = get_service_inbound_api(inbound_api_id, service_id)
|
||||
|
||||
reset_service_inbound_api(service_inbound_api=to_update,
|
||||
updated_by_id=data["updated_by_id"],
|
||||
url=data.get("url", None),
|
||||
bearer_token=data.get("bearer_token", None))
|
||||
return jsonify(data=to_update.serialize()), 200
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/inbound-api/<uuid:inbound_api_id>', methods=["GET"])
|
||||
def fetch_service_inbound_api(service_id, inbound_api_id):
|
||||
inbound_api = get_service_inbound_api(inbound_api_id, service_id)
|
||||
|
||||
return jsonify(data=inbound_api.serialize()), 200
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/delivery-receipt-api', methods=['POST'])
|
||||
def create_service_callback_api(service_id):
|
||||
data = request.get_json()
|
||||
validate(data, create_service_callback_api_schema)
|
||||
data["service_id"] = service_id
|
||||
callback_api = ServiceCallbackApi(**data)
|
||||
try:
|
||||
save_service_callback_api(callback_api)
|
||||
except SQLAlchemyError as e:
|
||||
return handle_sql_error(e, 'service_callback_api')
|
||||
|
||||
return jsonify(data=callback_api.serialize()), 201
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/delivery-receipt-api/<uuid:callback_api_id>', methods=['POST'])
|
||||
def update_service_callback_api(service_id, callback_api_id):
|
||||
data = request.get_json()
|
||||
validate(data, update_service_callback_api_schema)
|
||||
|
||||
to_update = get_service_callback_api(callback_api_id, service_id)
|
||||
|
||||
reset_service_callback_api(service_callback_api=to_update,
|
||||
updated_by_id=data["updated_by_id"],
|
||||
url=data.get("url", None),
|
||||
bearer_token=data.get("bearer_token", None))
|
||||
return jsonify(data=to_update.serialize()), 200
|
||||
|
||||
|
||||
@service_callback_blueprint.route('/delivery-receipt-api/<uuid:callback_api_id>', methods=["GET"])
|
||||
def fetch_service_callback_api(service_id, callback_api_id):
|
||||
callback_api = get_service_callback_api(callback_api_id, service_id)
|
||||
|
||||
return jsonify(data=callback_api.serialize()), 200
|
||||
|
||||
|
||||
def handle_sql_error(e, table_name):
|
||||
if hasattr(e, 'orig') and hasattr(e.orig, 'pgerror') and e.orig.pgerror \
|
||||
and ('duplicate key value violates unique constraint "ix_{}_service_id"'.format(table_name)
|
||||
in e.orig.pgerror):
|
||||
return jsonify(
|
||||
result='error',
|
||||
message={'name': ["You can only have one URL and bearer token for your service."]}
|
||||
), 400
|
||||
elif hasattr(e, 'orig') and hasattr(e.orig, 'pgerror') and e.orig.pgerror \
|
||||
and ('insert or update on table "{0}" violates '
|
||||
'foreign key constraint "{0}_service_id_fkey"'.format(table_name)
|
||||
in e.orig.pgerror):
|
||||
return jsonify(result='error', message="No result found"), 404
|
||||
else:
|
||||
raise e
|
||||
@@ -7,7 +7,6 @@ from flask import (
|
||||
current_app,
|
||||
Blueprint
|
||||
)
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from app.dao import notifications_dao
|
||||
@@ -18,11 +17,6 @@ from app.dao.api_key_dao import (
|
||||
get_unsigned_secret,
|
||||
expire_api_key)
|
||||
from app.dao.inbound_numbers_dao import dao_allocate_number_for_service
|
||||
from app.dao.service_inbound_api_dao import (
|
||||
save_service_inbound_api,
|
||||
reset_service_inbound_api,
|
||||
get_service_inbound_api
|
||||
)
|
||||
from app.dao.service_sms_sender_dao import (
|
||||
dao_add_sms_sender_for_service,
|
||||
dao_update_service_sms_sender,
|
||||
@@ -72,17 +66,9 @@ from app.errors import (
|
||||
InvalidRequest,
|
||||
register_errors
|
||||
)
|
||||
|
||||
from app.models import (
|
||||
Service,
|
||||
ServiceInboundApi
|
||||
)
|
||||
from app.models import Service
|
||||
from app.schema_validation import validate
|
||||
from app.service import statistics
|
||||
from app.service.service_inbound_api_schema import (
|
||||
service_inbound_api,
|
||||
update_service_inbound_api_schema
|
||||
)
|
||||
from app.service.service_senders_schema import (
|
||||
add_service_email_reply_to_request,
|
||||
add_service_letter_contact_block_request,
|
||||
@@ -540,58 +526,6 @@ def get_monthly_template_usage(service_id):
|
||||
raise InvalidRequest('Year must be a number', status_code=400)
|
||||
|
||||
|
||||
@service_blueprint.route('/<uuid:service_id>/inbound-api', methods=['POST'])
|
||||
def create_service_inbound_api(service_id):
|
||||
data = request.get_json()
|
||||
validate(data, service_inbound_api)
|
||||
data["service_id"] = service_id
|
||||
inbound_api = ServiceInboundApi(**data)
|
||||
try:
|
||||
save_service_inbound_api(inbound_api)
|
||||
except SQLAlchemyError as e:
|
||||
return handle_sql_errror(e)
|
||||
|
||||
return jsonify(data=inbound_api.serialize()), 201
|
||||
|
||||
|
||||
@service_blueprint.route('/<uuid:service_id>/inbound-api/<uuid:inbound_api_id>', methods=['POST'])
|
||||
def update_service_inbound_api(service_id, inbound_api_id):
|
||||
data = request.get_json()
|
||||
validate(data, update_service_inbound_api_schema)
|
||||
|
||||
to_update = get_service_inbound_api(inbound_api_id, service_id)
|
||||
|
||||
reset_service_inbound_api(service_inbound_api=to_update,
|
||||
updated_by_id=data["updated_by_id"],
|
||||
url=data.get("url", None),
|
||||
bearer_token=data.get("bearer_token", None))
|
||||
return jsonify(data=to_update.serialize()), 200
|
||||
|
||||
|
||||
@service_blueprint.route('/<uuid:service_id>/inbound-api/<uuid:inbound_api_id>', methods=["GET"])
|
||||
def fetch_service_inbound_api(service_id, inbound_api_id):
|
||||
inbound_api = get_service_inbound_api(inbound_api_id, service_id)
|
||||
|
||||
return jsonify(data=inbound_api.serialize()), 200
|
||||
|
||||
|
||||
def handle_sql_errror(e):
|
||||
if hasattr(e, 'orig') and hasattr(e.orig, 'pgerror') and e.orig.pgerror \
|
||||
and ('duplicate key value violates unique constraint "ix_service_inbound_api_service_id"'
|
||||
in e.orig.pgerror):
|
||||
return jsonify(
|
||||
result='error',
|
||||
message={'name': ["You can only have one URL and bearer token for your service."]}
|
||||
), 400
|
||||
elif hasattr(e, 'orig') and hasattr(e.orig, 'pgerror') and e.orig.pgerror \
|
||||
and ('insert or update on table "service_inbound_api" violates '
|
||||
'foreign key constraint "service_inbound_api_service_id_fkey"'
|
||||
in e.orig.pgerror):
|
||||
return jsonify(result='error', message="No result found"), 404
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
@service_blueprint.route('/<uuid:service_id>/send-notification', methods=['POST'])
|
||||
def create_one_off_notification(service_id):
|
||||
resp = send_one_off_notification(service_id, request.get_json())
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from app.schema_validation.definitions import uuid, https_url
|
||||
|
||||
service_inbound_api = {
|
||||
create_service_callback_api_schema = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "POST service inbound api schema",
|
||||
"description": "POST service callback/inbound api schema",
|
||||
"type": "object",
|
||||
"title": "Create service inbound api",
|
||||
"title": "Create service callback/inbound api",
|
||||
"properties": {
|
||||
"url": https_url,
|
||||
"bearer_token": {"type": "string", "minLength": 10},
|
||||
@@ -13,11 +13,11 @@ service_inbound_api = {
|
||||
"required": ["url", "bearer_token", "updated_by_id"]
|
||||
}
|
||||
|
||||
update_service_inbound_api_schema = {
|
||||
update_service_callback_api_schema = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "POST service inbound api schema",
|
||||
"description": "POST service callback/inbound api schema",
|
||||
"type": "object",
|
||||
"title": "Create service inbound api",
|
||||
"title": "Create service callback/inbound api",
|
||||
"properties": {
|
||||
"url": https_url,
|
||||
"bearer_token": {"type": "string", "minLength": 10},
|
||||
129
tests/app/dao/test_service_callback_api_dao.py
Normal file
129
tests/app/dao/test_service_callback_api_dao.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app import encryption
|
||||
from app.dao.service_callback_api_dao import (
|
||||
save_service_callback_api,
|
||||
reset_service_callback_api,
|
||||
get_service_callback_api,
|
||||
get_service_callback_api_for_service)
|
||||
from app.models import ServiceCallbackApi
|
||||
from tests.app.db import create_service_callback_api
|
||||
|
||||
|
||||
def test_save_service_callback_api(sample_service):
|
||||
service_callback_api = ServiceCallbackApi(
|
||||
service_id=sample_service.id,
|
||||
url="https://some_service/callback_endpoint",
|
||||
bearer_token="some_unique_string",
|
||||
updated_by_id=sample_service.users[0].id
|
||||
)
|
||||
|
||||
save_service_callback_api(service_callback_api)
|
||||
|
||||
results = ServiceCallbackApi.query.all()
|
||||
assert len(results) == 1
|
||||
callback_api = results[0]
|
||||
assert callback_api.id is not None
|
||||
assert callback_api.service_id == sample_service.id
|
||||
assert callback_api.updated_by_id == sample_service.users[0].id
|
||||
assert callback_api.url == "https://some_service/callback_endpoint"
|
||||
assert callback_api.bearer_token == "some_unique_string"
|
||||
assert callback_api._bearer_token != "some_unique_string"
|
||||
assert callback_api.updated_at is None
|
||||
|
||||
versioned = ServiceCallbackApi.get_history_model().query.filter_by(id=callback_api.id).one()
|
||||
assert versioned.id == callback_api.id
|
||||
assert versioned.service_id == sample_service.id
|
||||
assert versioned.updated_by_id == sample_service.users[0].id
|
||||
assert versioned.url == "https://some_service/callback_endpoint"
|
||||
assert encryption.decrypt(versioned._bearer_token) == "some_unique_string"
|
||||
assert versioned.updated_at is None
|
||||
assert versioned.version == 1
|
||||
|
||||
|
||||
def test_save_service_callback_api_fails_if_service_does_not_exist(notify_db, notify_db_session):
|
||||
service_callback_api = ServiceCallbackApi(
|
||||
service_id=uuid.uuid4(),
|
||||
url="https://some_service/callback_endpoint",
|
||||
bearer_token="some_unique_string",
|
||||
updated_by_id=uuid.uuid4()
|
||||
)
|
||||
|
||||
with pytest.raises(SQLAlchemyError):
|
||||
save_service_callback_api(service_callback_api)
|
||||
|
||||
|
||||
def test_update_service_callback_api(sample_service):
|
||||
service_callback_api = ServiceCallbackApi(
|
||||
service_id=sample_service.id,
|
||||
url="https://some_service/callback_endpoint",
|
||||
bearer_token="some_unique_string",
|
||||
updated_by_id=sample_service.users[0].id
|
||||
)
|
||||
|
||||
save_service_callback_api(service_callback_api)
|
||||
results = ServiceCallbackApi.query.all()
|
||||
assert len(results) == 1
|
||||
saved_callback_api = results[0]
|
||||
|
||||
reset_service_callback_api(saved_callback_api, updated_by_id=sample_service.users[0].id,
|
||||
url="https://some_service/changed_url")
|
||||
updated_results = ServiceCallbackApi.query.all()
|
||||
assert len(updated_results) == 1
|
||||
updated = updated_results[0]
|
||||
assert updated.id is not None
|
||||
assert updated.service_id == sample_service.id
|
||||
assert updated.updated_by_id == sample_service.users[0].id
|
||||
assert updated.url == "https://some_service/changed_url"
|
||||
assert updated.bearer_token == "some_unique_string"
|
||||
assert updated._bearer_token != "some_unique_string"
|
||||
assert updated.updated_at is not None
|
||||
|
||||
versioned_results = ServiceCallbackApi.get_history_model().query.filter_by(id=saved_callback_api.id).all()
|
||||
assert len(versioned_results) == 2
|
||||
for x in versioned_results:
|
||||
if x.version == 1:
|
||||
assert x.url == "https://some_service/callback_endpoint"
|
||||
assert not x.updated_at
|
||||
elif x.version == 2:
|
||||
assert x.url == "https://some_service/changed_url"
|
||||
assert x.updated_at
|
||||
else:
|
||||
pytest.fail("version should not exist")
|
||||
assert x.id is not None
|
||||
assert x.service_id == sample_service.id
|
||||
assert x.updated_by_id == sample_service.users[0].id
|
||||
assert encryption.decrypt(x._bearer_token) == "some_unique_string"
|
||||
|
||||
|
||||
def test_get_service_callback_api(sample_service):
|
||||
service_callback_api = ServiceCallbackApi(
|
||||
service_id=sample_service.id,
|
||||
url="https://some_service/callback_endpoint",
|
||||
bearer_token="some_unique_string",
|
||||
updated_by_id=sample_service.users[0].id
|
||||
)
|
||||
save_service_callback_api(service_callback_api)
|
||||
|
||||
callback_api = get_service_callback_api(service_callback_api.id, sample_service.id)
|
||||
assert callback_api.id is not None
|
||||
assert callback_api.service_id == sample_service.id
|
||||
assert callback_api.updated_by_id == sample_service.users[0].id
|
||||
assert callback_api.url == "https://some_service/callback_endpoint"
|
||||
assert callback_api.bearer_token == "some_unique_string"
|
||||
assert callback_api._bearer_token != "some_unique_string"
|
||||
assert callback_api.updated_at is None
|
||||
|
||||
|
||||
def test_get_service_callback_api_for_service(sample_service):
|
||||
service_callback_api = create_service_callback_api(service=sample_service)
|
||||
result = get_service_callback_api_for_service(sample_service.id)
|
||||
assert result.id == service_callback_api.id
|
||||
assert result.url == service_callback_api.url
|
||||
assert result.bearer_token == service_callback_api.bearer_token
|
||||
assert result.created_at == service_callback_api.created_at
|
||||
assert result.updated_at == service_callback_api.updated_at
|
||||
assert result.updated_by_id == service_callback_api.updated_by_id
|
||||
@@ -4,6 +4,7 @@ import uuid
|
||||
from app import db
|
||||
from app.dao.jobs_dao import dao_create_job
|
||||
from app.dao.service_inbound_api_dao import save_service_inbound_api
|
||||
from app.dao.service_callback_api_dao import save_service_callback_api
|
||||
from app.dao.service_sms_sender_dao import update_existing_sms_sender_with_inbound_number, dao_update_service_sms_sender
|
||||
from app.models import (
|
||||
ApiKey,
|
||||
@@ -17,6 +18,7 @@ from app.models import (
|
||||
Service,
|
||||
ServiceEmailReplyTo,
|
||||
ServiceInboundApi,
|
||||
ServiceCallbackApi,
|
||||
ServiceLetterContact,
|
||||
ScheduledNotification,
|
||||
ServicePermission,
|
||||
@@ -296,6 +298,20 @@ def create_service_inbound_api(
|
||||
return service_inbound_api
|
||||
|
||||
|
||||
def create_service_callback_api(
|
||||
service,
|
||||
url="https://something.com",
|
||||
bearer_token="some_super_secret",
|
||||
):
|
||||
service_callback_api = ServiceCallbackApi(service_id=service.id,
|
||||
url=url,
|
||||
bearer_token=bearer_token,
|
||||
updated_by_id=service.users[0].id
|
||||
)
|
||||
save_service_callback_api(service_callback_api)
|
||||
return service_callback_api
|
||||
|
||||
|
||||
def create_organisation(colour='blue', logo='test_x2.png', name='test_org_1'):
|
||||
data = {
|
||||
'colour': colour,
|
||||
|
||||
165
tests/app/service/test_callback_rest.py
Normal file
165
tests/app/service/test_callback_rest.py
Normal file
@@ -0,0 +1,165 @@
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from tests import create_authorization_header
|
||||
|
||||
from tests.app.db import (
|
||||
create_service_inbound_api,
|
||||
create_service_callback_api
|
||||
)
|
||||
|
||||
|
||||
def test_create_service_inbound_api(client, sample_service):
|
||||
data = {
|
||||
"url": "https://some_service/inbound-sms",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/inbound-api'.format(sample_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["id"]
|
||||
assert resp_json["service_id"] == str(sample_service.id)
|
||||
assert resp_json["url"] == "https://some_service/inbound-sms"
|
||||
assert resp_json["updated_by_id"] == str(sample_service.users[0].id)
|
||||
assert resp_json["created_at"]
|
||||
assert not resp_json["updated_at"]
|
||||
|
||||
|
||||
def test_set_service_inbound_api_raises_404_when_service_does_not_exist(client):
|
||||
data = {
|
||||
"url": "https://some_service/inbound-sms",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/inbound-api'.format(uuid.uuid4()),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert json.loads(response.get_data(as_text=True))['message'] == 'No result found'
|
||||
|
||||
|
||||
def test_update_service_inbound_api_updates_url(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service,
|
||||
url="https://original_url.com")
|
||||
|
||||
data = {
|
||||
"url": "https://another_url.com",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["url"] == "https://another_url.com"
|
||||
assert service_inbound_api.url == "https://another_url.com"
|
||||
|
||||
|
||||
def test_update_service_inbound_api_updates_bearer_token(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service,
|
||||
bearer_token="some_super_secret")
|
||||
data = {
|
||||
"bearer_token": "different_token",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
assert service_inbound_api.bearer_token == "different_token"
|
||||
|
||||
|
||||
def test_fetch_service_inbound_api(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service)
|
||||
|
||||
response = client.get("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
headers=[create_authorization_header()])
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.get_data(as_text=True))["data"] == service_inbound_api.serialize()
|
||||
|
||||
|
||||
def test_create_service_callback_api(client, sample_service):
|
||||
data = {
|
||||
"url": "https://some_service/delivery-receipt-endpoint",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/delivery-receipt-api'.format(sample_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["id"]
|
||||
assert resp_json["service_id"] == str(sample_service.id)
|
||||
assert resp_json["url"] == "https://some_service/delivery-receipt-endpoint"
|
||||
assert resp_json["updated_by_id"] == str(sample_service.users[0].id)
|
||||
assert resp_json["created_at"]
|
||||
assert not resp_json["updated_at"]
|
||||
|
||||
|
||||
def test_set_service_callback_api_raises_404_when_service_does_not_exist(client, notify_db_session):
|
||||
data = {
|
||||
"url": "https://some_service/delivery-receipt-endpoint",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/delivery-receipt-api'.format(uuid.uuid4()),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert json.loads(response.get_data(as_text=True))['message'] == 'No result found'
|
||||
|
||||
|
||||
def test_update_service_callback_api_updates_url(client, sample_service):
|
||||
service_callback_api = create_service_callback_api(service=sample_service,
|
||||
url="https://original_url.com")
|
||||
|
||||
data = {
|
||||
"url": "https://another_url.com",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/delivery-receipt-api/{}".format(sample_service.id, service_callback_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["url"] == "https://another_url.com"
|
||||
assert service_callback_api.url == "https://another_url.com"
|
||||
|
||||
|
||||
def test_update_service_callback_api_updates_bearer_token(client, sample_service):
|
||||
service_callback_api = create_service_callback_api(service=sample_service,
|
||||
bearer_token="some_super_secret")
|
||||
data = {
|
||||
"bearer_token": "different_token",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/delivery-receipt-api/{}".format(sample_service.id, service_callback_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
assert service_callback_api.bearer_token == "different_token"
|
||||
|
||||
|
||||
def test_fetch_service_callback_api(client, sample_service):
|
||||
service_callback_api = create_service_callback_api(service=sample_service)
|
||||
|
||||
response = client.get("/service/{}/delivery-receipt-api/{}".format(sample_service.id, service_callback_api.id),
|
||||
headers=[create_authorization_header()])
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.get_data(as_text=True))["data"] == service_callback_api.serialize()
|
||||
@@ -30,7 +30,6 @@ from tests.app.conftest import (
|
||||
from tests.app.db import (
|
||||
create_service,
|
||||
create_template,
|
||||
create_service_inbound_api,
|
||||
create_notification,
|
||||
create_reply_to_email,
|
||||
create_letter_contact,
|
||||
@@ -2164,84 +2163,6 @@ def test_search_for_notification_by_to_field_returns_content(
|
||||
assert notifications[0]['template']['content'] == 'Hello (( Name))\nYour thing is due soon'
|
||||
|
||||
|
||||
def test_create_service_inbound_api(client, sample_service):
|
||||
data = {
|
||||
"url": "https://some_service/inbound-sms",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/inbound-api'.format(sample_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["id"]
|
||||
assert resp_json["service_id"] == str(sample_service.id)
|
||||
assert resp_json["url"] == "https://some_service/inbound-sms"
|
||||
assert resp_json["updated_by_id"] == str(sample_service.users[0].id)
|
||||
assert resp_json["created_at"]
|
||||
assert not resp_json["updated_at"]
|
||||
|
||||
|
||||
def test_set_service_inbound_api_raises_404_when_service_does_not_exist(client):
|
||||
data = {
|
||||
"url": "https://some_service/inbound-sms",
|
||||
"bearer_token": "some-unique-string",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
response = client.post(
|
||||
'/service/{}/inbound-api'.format(uuid.uuid4()),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert json.loads(response.get_data(as_text=True))['message'] == 'No result found'
|
||||
|
||||
|
||||
def test_update_service_inbound_api_updates_url(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service,
|
||||
url="https://original_url.com")
|
||||
|
||||
data = {
|
||||
"url": "https://another_url.com",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
resp_json = json.loads(response.get_data(as_text=True))["data"]
|
||||
assert resp_json["url"] == "https://another_url.com"
|
||||
assert service_inbound_api.url == "https://another_url.com"
|
||||
|
||||
|
||||
def test_update_service_inbound_api_updates_bearer_token(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service,
|
||||
bearer_token="some_super_secret")
|
||||
data = {
|
||||
"bearer_token": "different_token",
|
||||
"updated_by_id": str(sample_service.users[0].id)
|
||||
}
|
||||
response = client.post("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
assert service_inbound_api.bearer_token == "different_token"
|
||||
|
||||
|
||||
def test_fetch_service_inbound_api(client, sample_service):
|
||||
service_inbound_api = create_service_inbound_api(service=sample_service)
|
||||
|
||||
response = client.get("/service/{}/inbound-api/{}".format(sample_service.id, service_inbound_api.id),
|
||||
headers=[create_authorization_header()])
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.get_data(as_text=True))["data"] == service_inbound_api.serialize()
|
||||
|
||||
|
||||
def test_send_one_off_notification(admin_request, mocker):
|
||||
service = create_service()
|
||||
template = create_template(service=service)
|
||||
|
||||
@@ -5,41 +5,42 @@ import pytest
|
||||
from jsonschema import ValidationError
|
||||
|
||||
from app.schema_validation import validate
|
||||
from app.service.service_inbound_api_schema import service_inbound_api
|
||||
from app.service.service_callback_api_schema import (
|
||||
update_service_callback_api_schema)
|
||||
|
||||
|
||||
def test_service_inbound_api_schema_validates():
|
||||
def test_service_callback_api_schema_validates():
|
||||
under_test = {"url": "https://some_url.for_service",
|
||||
"bearer_token": "something_ten_chars",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
|
||||
validated = validate(under_test, service_inbound_api)
|
||||
validated = validate(under_test, update_service_callback_api_schema)
|
||||
assert validated == under_test
|
||||
|
||||
|
||||
@pytest.mark.parametrize("url", ["not a url", "https not a url", "http://valid.com"])
|
||||
def test_service_inbound_api_schema_errors_for_url_not_valid_url(url):
|
||||
def test_service_callback_api_schema_errors_for_url_not_valid_url(url):
|
||||
under_test = {"url": url,
|
||||
"bearer_token": "something_ten_chars",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
|
||||
with pytest.raises(ValidationError) as e:
|
||||
validate(under_test, service_inbound_api)
|
||||
validate(under_test, update_service_callback_api_schema)
|
||||
errors = json.loads(str(e.value)).get('errors')
|
||||
assert len(errors) == 1
|
||||
assert errors[0]['message'] == "url is not a valid https url"
|
||||
|
||||
|
||||
def test_service_inbound_api_schema_bearer_token_under_ten_char():
|
||||
def test_service_callback_api_schema_bearer_token_under_ten_char():
|
||||
under_test = {"url": "https://some_url.for_service",
|
||||
"bearer_token": "shorty",
|
||||
"updated_by_id": str(uuid.uuid4())
|
||||
}
|
||||
|
||||
with pytest.raises(ValidationError) as e:
|
||||
validate(under_test, service_inbound_api)
|
||||
validate(under_test, update_service_callback_api_schema)
|
||||
errors = json.loads(str(e.value)).get('errors')
|
||||
assert len(errors) == 1
|
||||
assert errors[0]['message'] == "bearer_token shorty is too short"
|
||||
|
||||
Reference in New Issue
Block a user