Allow service to set callback url for notifications

This commit is contained in:
chrisw
2017-12-04 15:07:11 +00:00
parent ac547623b1
commit 43c14fb756
12 changed files with 523 additions and 268 deletions

View File

@@ -717,15 +717,38 @@ class ServiceInboundNumberForm(Form):
)
class ServiceInboundApiForm(Form):
url = StringField("Callback URL",
validators=[DataRequired(message='Cant be empty'),
Regexp(regex="^https.*",
message='Must be a valid https URL')]
)
bearer_token = PasswordFieldShowHasContent("Bearer token",
validators=[DataRequired(message='Cant 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='Cant be empty'),
Regexp(regex="^https.*", message='Must be a valid https URL')]
)
outbound_bearer_token = PasswordFieldShowHasContent(
"Bearer token",
validators=[DataRequired(message='Cant 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('Cant 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('Cant be empty')
elif len(field.data) < 10:
raise ValidationError('Must be at least 10 characters')
class InternationalSMSForm(Form):

View File

@@ -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/<service_id>/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/<service_id>/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,
)

View File

@@ -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_id>/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_id>/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,
)