Merge pull request #2180 from alphagov/service-model

Make a service model
This commit is contained in:
Chris Hill-Scott
2018-07-31 13:31:09 +01:00
committed by GitHub
20 changed files with 156 additions and 111 deletions
+7 -1
View File
@@ -40,6 +40,7 @@ from werkzeug.local import LocalProxy
from app import proxy_fix from app import proxy_fix
from app.config import configs from app.config import configs
from app.asset_fingerprinter import AssetFingerprinter from app.asset_fingerprinter import AssetFingerprinter
from app.notify_client.models import Service
from app.navigation import ( from app.navigation import (
CaseworkNavigation, CaseworkNavigation,
HeaderNavigation, HeaderNavigation,
@@ -94,8 +95,13 @@ billing_api_client = BillingAPIClient()
complaint_api_client = ComplaintApiClient() complaint_api_client = ComplaintApiClient()
platform_stats_api_client = PlatformStatsAPIClient() platform_stats_api_client = PlatformStatsAPIClient()
# The current service attached to the request stack. # The current service attached to the request stack.
current_service = LocalProxy(partial(_lookup_req_object, 'service')) def _get_current_service():
return Service(_lookup_req_object('service'))
current_service = LocalProxy(_get_current_service)
# The current organisation attached to the request stack. # The current organisation attached to the request stack.
current_organisation = LocalProxy(partial(_lookup_req_object, 'organisation')) current_organisation = LocalProxy(partial(_lookup_req_object, 'organisation'))
+15 -15
View File
@@ -37,7 +37,7 @@ dummy_bearer_token = 'bearer_token_set'
@user_has_permissions('manage_api_keys') @user_has_permissions('manage_api_keys')
def api_integration(service_id): def api_integration(service_id):
callbacks_link = ( callbacks_link = (
'.api_callbacks' if 'inbound_sms' in current_service['permissions'] '.api_callbacks' if current_service.has_permission('inbound_sms')
else '.delivery_status_callback' else '.delivery_status_callback'
) )
return render_template( return render_template(
@@ -98,13 +98,13 @@ def create_api_key(service_id):
(KEY_TYPE_TEST, 'Test pretends to send messages'), (KEY_TYPE_TEST, 'Test pretends to send messages'),
] ]
disabled_options, option_hints = [], {} disabled_options, option_hints = [], {}
if current_service['restricted']: if current_service.trial_mode:
disabled_options = [KEY_TYPE_NORMAL] disabled_options = [KEY_TYPE_NORMAL]
option_hints[KEY_TYPE_NORMAL] = Markup( option_hints[KEY_TYPE_NORMAL] = Markup(
'Not available because your service is in ' 'Not available because your service is in '
'<a href="{}#trial-mode">trial mode</a>'.format(url_for(".using_notify")) '<a href="{}#trial-mode">trial mode</a>'.format(url_for(".using_notify"))
) )
if 'letter' in current_service['permissions']: if current_service.has_permission('letter'):
option_hints[KEY_TYPE_TEAM] = 'Cant be used to send letters' option_hints[KEY_TYPE_TEAM] = 'Cant be used to send letters'
if form.validate_on_submit(): if form.validate_on_submit():
if form.key_type.data in disabled_options: if form.key_type.data in disabled_options:
@@ -148,14 +148,14 @@ def revoke_api_key(service_id, key_id):
def get_apis(): def get_apis():
callback_api = None callback_api = None
inbound_api = None inbound_api = None
if current_service['service_callback_api']: if current_service.service_callback_api:
callback_api = service_api_client.get_service_callback_api( callback_api = service_api_client.get_service_callback_api(
current_service['id'], current_service.id,
current_service.get('service_callback_api')[0] current_service.get('service_callback_api')[0]
) )
if current_service['inbound_api']: if current_service.inbound_api:
inbound_api = service_api_client.get_service_inbound_api( inbound_api = service_api_client.get_service_inbound_api(
current_service['id'], current_service.id,
current_service.get('inbound_api')[0] current_service.get('inbound_api')[0]
) )
@@ -172,7 +172,7 @@ def check_token_against_dummy_bearer(token):
@main.route("/services/<service_id>/api/callbacks", methods=['GET']) @main.route("/services/<service_id>/api/callbacks", methods=['GET'])
@login_required @login_required
def api_callbacks(service_id): def api_callbacks(service_id):
if 'inbound_sms' not in current_service['permissions']: if not current_service.has_permission('inbound_sms'):
return redirect(url_for('.delivery_status_callback', service_id=service_id)) return redirect(url_for('.delivery_status_callback', service_id=service_id))
delivery_status_callback, received_text_messages_callback = get_apis() delivery_status_callback, received_text_messages_callback = get_apis()
@@ -186,10 +186,10 @@ def api_callbacks(service_id):
def get_delivery_status_callback_details(): def get_delivery_status_callback_details():
if current_service['service_callback_api']: if current_service.service_callback_api:
return service_api_client.get_service_callback_api( return service_api_client.get_service_callback_api(
current_service['id'], current_service.id,
current_service.get('service_callback_api')[0] current_service.service_callback_api[0]
) )
@@ -198,7 +198,7 @@ def get_delivery_status_callback_details():
def delivery_status_callback(service_id): def delivery_status_callback(service_id):
delivery_status_callback = get_delivery_status_callback_details() delivery_status_callback = get_delivery_status_callback_details()
back_link = ( back_link = (
'.api_callbacks' if 'inbound_sms' in current_service['permissions'] '.api_callbacks' if current_service.has_permission('inbound_sms')
else '.api_integration' else '.api_integration'
) )
@@ -248,9 +248,9 @@ def delivery_status_callback(service_id):
def get_received_text_messages_callback(): def get_received_text_messages_callback():
if current_service['inbound_api']: if current_service.inbound_api:
return service_api_client.get_service_inbound_api( return service_api_client.get_service_inbound_api(
current_service['id'], current_service.id,
current_service.get('inbound_api')[0] current_service.get('inbound_api')[0]
) )
@@ -258,7 +258,7 @@ def get_received_text_messages_callback():
@main.route("/services/<service_id>/api/callbacks/received-text-messages-callback", methods=['GET', 'POST']) @main.route("/services/<service_id>/api/callbacks/received-text-messages-callback", methods=['GET', 'POST'])
@login_required @login_required
def received_text_messages_callback(service_id): def received_text_messages_callback(service_id):
if 'inbound_sms' not in current_service['permissions']: if not current_service.has_permission('inbound_sms'):
return redirect(url_for('.api_integration', service_id=service_id)) return redirect(url_for('.api_integration', service_id=service_id))
received_text_messages_callback = get_received_text_messages_callback() received_text_messages_callback = get_received_text_messages_callback()
+4 -4
View File
@@ -152,7 +152,7 @@ def usage(service_id):
yearly_usage = billing_api_client.get_service_usage_ft(service_id, year) yearly_usage = billing_api_client.get_service_usage_ft(service_id, year)
usage_template = 'views/usage.html' usage_template = 'views/usage.html'
if 'letter' in current_service['permissions']: if current_service.has_permission('letter'):
usage_template = 'views/usage-with-letters.html' usage_template = 'views/usage-with-letters.html'
return render_template( return render_template(
usage_template, usage_template,
@@ -238,7 +238,7 @@ def inbox_download(service_id):
def get_inbox_partials(service_id): def get_inbox_partials(service_id):
page = int(request.args.get('page', 1)) page = int(request.args.get('page', 1))
if 'inbound_sms' not in current_service['permissions']: if not current_service.has_permission('inbound_sms'):
abort(403) abort(403)
inbound_messages_data = service_api_client.get_most_recent_inbound_sms(service_id, page=page) inbound_messages_data = service_api_client.get_most_recent_inbound_sms(service_id, page=page)
@@ -290,7 +290,7 @@ def get_dashboard_partials(service_id):
stats = service_api_client.get_service_statistics(service_id, today_only=False) stats = service_api_client.get_service_statistics(service_id, today_only=False)
column_width, max_notifiction_count = get_column_properties( column_width, max_notifiction_count = get_column_properties(
number_of_columns=( number_of_columns=(
3 if 'letter' in current_service['permissions'] else 2 3 if current_service.has_permission('letter') else 2
) )
) )
dashboard_totals = get_dashboard_totals(stats), dashboard_totals = get_dashboard_totals(stats),
@@ -310,7 +310,7 @@ def get_dashboard_partials(service_id):
'views/dashboard/_inbox.html', 'views/dashboard/_inbox.html',
inbound_sms_summary=( inbound_sms_summary=(
service_api_client.get_inbound_sms_summary(service_id) service_api_client.get_inbound_sms_summary(service_id)
if 'inbound_sms' in current_service['permissions'] else None if current_service.has_permission('inbound_sms') else None
), ),
), ),
'totals': render_template( 'totals': render_template(
+2 -2
View File
@@ -104,8 +104,8 @@ def feedback(ticket_type):
user_name = form.name.data or None user_name = form.name.data or None
if current_service: if current_service:
service_string = 'Service: "{name}"\n{url}\n'.format( service_string = 'Service: "{name}"\n{url}\n'.format(
name=current_service['name'], name=current_service.name,
url=url_for('main.service_dashboard', service_id=current_service['id'], _external=True) url=url_for('main.service_dashboard', service_id=current_service.id, _external=True)
) )
else: else:
service_string = '' service_string = ''
+4 -4
View File
@@ -155,7 +155,7 @@ def view_job_updates(service_id, job_id):
return jsonify(**get_job_partials( return jsonify(**get_job_partials(
job, job,
service_api_client.get_service_template( service_api_client.get_service_template(
service_id=current_service['id'], service_id=current_service.id,
template_id=job['template'], template_id=job['template'],
version=job['template_version'] version=job['template_version']
)['data'], )['data'],
@@ -177,7 +177,7 @@ def view_notifications(service_id, message_type=None):
search_form=SearchNotificationsForm(to=request.form.get('to', '')), search_form=SearchNotificationsForm(to=request.form.get('to', '')),
download_link=url_for( download_link=url_for(
'.download_notifications_csv', '.download_notifications_csv',
service_id=current_service['id'], service_id=current_service.id,
message_type=message_type, message_type=message_type,
status=request.args.get('status') status=request.args.get('status')
) )
@@ -242,7 +242,7 @@ def get_notifications(service_id, message_type, status_override=None):
if message_type: if message_type:
download_link = url_for( download_link = url_for(
'.view_notifications_csv', '.view_notifications_csv',
service_id=current_service['id'], service_id=current_service.id,
message_type=message_type, message_type=message_type,
status=request.args.get('status') status=request.args.get('status')
) )
@@ -380,7 +380,7 @@ def get_job_partials(job, template):
percentage_complete=(job['notifications_requested'] / job['notification_count'] * 100), percentage_complete=(job['notifications_requested'] / job['notification_count'] * 100),
download_link=url_for( download_link=url_for(
'.view_job_csv', '.view_job_csv',
service_id=current_service['id'], service_id=current_service.id,
job_id=job['id'], job_id=job['id'],
status=request.args.get('status') status=request.args.get('status')
), ),
+4 -4
View File
@@ -48,14 +48,14 @@ def manage_users(service_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def invite_user(service_id): def invite_user(service_id):
if 'caseworking' in current_service['permissions']: if current_service.has_permission('caseworking'):
form = CaseworkingInviteUserForm form = CaseworkingInviteUserForm
else: else:
form = AdminInviteUserForm form = AdminInviteUserForm
form = form(invalid_email_address=current_user.email_address) form = form(invalid_email_address=current_user.email_address)
service_has_email_auth = 'email_auth' in current_service['permissions'] service_has_email_auth = current_service.has_permission('email_auth')
if not service_has_email_auth: if not service_has_email_auth:
form.login_authentication.data = 'sms_auth' form.login_authentication.data = 'sms_auth'
@@ -83,13 +83,13 @@ def invite_user(service_id):
@login_required @login_required
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def edit_user_permissions(service_id, user_id): def edit_user_permissions(service_id, user_id):
service_has_email_auth = 'email_auth' in current_service['permissions'] service_has_email_auth = current_service.has_permission('email_auth')
# TODO we should probably using the service id here in the get user # TODO we should probably using the service id here in the get user
# call as well. eg. /user/<user_id>?&service=service_id # call as well. eg. /user/<user_id>?&service=service_id
user = user_api_client.get_user(user_id) user = user_api_client.get_user(user_id)
user_has_no_mobile_number = user.mobile_number is None user_has_no_mobile_number = user.mobile_number is None
if 'caseworking' in current_service['permissions']: if current_service.has_permission('caseworking'):
form = partial( form = partial(
CaseworkingPermissionsForm, CaseworkingPermissionsForm,
user_type='admin' if user.has_permission_for_service(service_id, 'view_activity') else 'caseworker', user_type='admin' if user.has_permission_for_service(service_id, 'view_activity') else 'caseworker',
+2 -2
View File
@@ -91,7 +91,7 @@ def view_notification(service_id, notification_id):
help=get_help_argument(), help=get_help_argument(),
estimated_letter_delivery_date=get_letter_timings(notification['created_at']).earliest_delivery, estimated_letter_delivery_date=get_letter_timings(notification['created_at']).earliest_delivery,
notification_id=notification['id'], notification_id=notification['id'],
can_receive_inbound=('inbound_sms' in current_service['permissions']), can_receive_inbound=(current_service.has_permission('inbound_sms')),
is_precompiled_letter=notification['template']['is_precompiled_letter'] is_precompiled_letter=notification['template']['is_precompiled_letter']
) )
@@ -188,6 +188,6 @@ def download_notifications_csv(service_id):
'Content-Disposition': 'inline; filename="{} - {} - {} report.csv"'.format( 'Content-Disposition': 'inline; filename="{} - {} - {} report.csv"'.format(
format_date_numeric(datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ")), format_date_numeric(datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ")),
filter_args['message_type'][0], filter_args['message_type'][0],
current_service['name']) current_service.name)
} }
) )
+8 -8
View File
@@ -116,7 +116,7 @@ def send_messages(service_id, template_id):
session['sender_id'] = None session['sender_id'] = None
db_template = service_api_client.get_service_template(service_id, template_id)['data'] db_template = service_api_client.get_service_template(service_id, template_id)['data']
if email_or_sms_not_enabled(db_template['template_type'], current_service['permissions']): if email_or_sms_not_enabled(db_template['template_type'], current_service.permissions):
return redirect(url_for( return redirect(url_for(
'.action_blocked', '.action_blocked',
service_id=service_id, service_id=service_id,
@@ -294,7 +294,7 @@ def send_test(service_id, template_id):
if db_template['template_type'] == 'letter': if db_template['template_type'] == 'letter':
session['sender_id'] = None session['sender_id'] = None
if email_or_sms_not_enabled(db_template['template_type'], current_service['permissions']): if email_or_sms_not_enabled(db_template['template_type'], current_service.permissions):
return redirect(url_for( return redirect(url_for(
'.action_blocked', '.action_blocked',
service_id=service_id, service_id=service_id,
@@ -401,7 +401,7 @@ def send_test_step(service_id, template_id, step_index):
dict_to_populate_from=get_normalised_placeholders_from_session(), dict_to_populate_from=get_normalised_placeholders_from_session(),
template_type=template.template_type, template_type=template.template_type,
optional_placeholder=optional_placeholder, optional_placeholder=optional_placeholder,
allow_international_phone_numbers='international_sms' in current_service['permissions'], allow_international_phone_numbers=current_service.has_permission('international_sms'),
) )
if form.validate_on_submit(): if form.validate_on_submit():
@@ -511,7 +511,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
users = user_api_client.get_users_for_service(service_id=service_id) users = user_api_client.get_users_for_service(service_id=service_id)
statistics = service_api_client.get_service_statistics(service_id, today_only=True) statistics = service_api_client.get_service_statistics(service_id, today_only=True)
remaining_messages = (current_service['message_limit'] - sum(stat['requested'] for stat in statistics.values())) remaining_messages = (current_service.message_limit - sum(stat['requested'] for stat in statistics.values()))
contents = s3download(service_id, upload_id) contents = s3download(service_id, upload_id)
@@ -549,9 +549,9 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
max_errors_shown=50, max_errors_shown=50,
whitelist=itertools.chain.from_iterable( whitelist=itertools.chain.from_iterable(
[user.name, user.mobile_number, user.email_address] for user in users [user.name, user.mobile_number, user.email_address] for user in users
) if current_service['restricted'] else None, ) if current_service.trial_mode else None,
remaining_messages=remaining_messages, remaining_messages=remaining_messages,
international_sms='international_sms' in current_service['permissions'], international_sms=current_service.has_permission('international_sms'),
) )
if request.args.get('from_test'): if request.args.get('from_test'):
@@ -585,7 +585,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
back_link=back_link, back_link=back_link,
help=get_help_argument(), help=get_help_argument(),
trying_to_send_letters_in_trial_mode=all(( trying_to_send_letters_in_trial_mode=all((
current_service['restricted'], current_service.trial_mode,
template.template_type == 'letter', template.template_type == 'letter',
not request.args.get('from_test'), not request.args.get('from_test'),
)), )),
@@ -873,7 +873,7 @@ def send_notification(service_id, template_id):
) )
except HTTPError as exception: except HTTPError as exception:
current_app.logger.info('Service {} could not send notification: "{}"'.format( current_app.logger.info('Service {} could not send notification: "{}"'.format(
current_service['id'], current_service.id,
exception.message exception.message
)) ))
return _check_notification(service_id, template_id, exception) return _check_notification(service_id, template_id, exception)
+46 -48
View File
@@ -62,8 +62,8 @@ def service_settings(service_id):
letter_branding_organisations = email_branding_client.get_letter_email_branding() letter_branding_organisations = email_branding_client.get_letter_email_branding()
organisation = organisations_client.get_service_organisation(service_id).get('name', None) organisation = organisations_client.get_service_organisation(service_id).get('name', None)
if current_service['email_branding']: if current_service.email_branding:
email_branding = email_branding_client.get_email_branding(current_service['email_branding'])['email_branding'] email_branding = email_branding_client.get_email_branding(current_service.email_branding)['email_branding']
else: else:
email_branding = None email_branding = None
@@ -93,7 +93,7 @@ def service_settings(service_id):
letter_branding=letter_branding_organisations.get( letter_branding=letter_branding_organisations.get(
current_service.get('dvla_organisation', '001') current_service.get('dvla_organisation', '001')
), ),
can_receive_inbound=('inbound_sms' in current_service['permissions']), can_receive_inbound=(current_service.has_permission('inbound_sms')),
inbound_number=disp_inbound_number, inbound_number=disp_inbound_number,
default_reply_to_email_address=default_reply_to_email_address, default_reply_to_email_address=default_reply_to_email_address,
reply_to_email_address_count=reply_to_email_address_count, reply_to_email_address_count=reply_to_email_address_count,
@@ -102,7 +102,7 @@ def service_settings(service_id):
default_sms_sender=default_sms_sender, default_sms_sender=default_sms_sender,
sms_sender_count=sms_sender_count, sms_sender_count=sms_sender_count,
free_sms_fragment_limit=free_sms_fragment_limit, free_sms_fragment_limit=free_sms_fragment_limit,
prefix_sms=current_service['prefix_sms'], prefix_sms=current_service.prefix_sms,
organisation=organisation, organisation=organisation,
) )
@@ -114,11 +114,11 @@ def service_name_change(service_id):
form = RenameServiceForm() form = RenameServiceForm()
if request.method == 'GET': if request.method == 'GET':
form.name.data = current_service['name'] form.name.data = current_service.name
if form.validate_on_submit(): if form.validate_on_submit():
if form.name.data == current_service['name']: if form.name.data == current_service.name:
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
unique_name = service_api_client.is_service_name_unique(service_id, form.name.data, email_safe(form.name.data)) unique_name = service_api_client.is_service_name_unique(service_id, form.name.data, email_safe(form.name.data))
@@ -149,7 +149,7 @@ def service_name_change_confirm(service_id):
if form.validate_on_submit(): if form.validate_on_submit():
try: try:
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
name=session['service_name_change'], name=session['service_name_change'],
email_from=email_safe(session['service_name_change']) email_from=email_safe(session['service_name_change'])
) )
@@ -201,7 +201,7 @@ def submit_request_to_go_live(service_id):
if form.validate_on_submit(): if form.validate_on_submit():
zendesk_client.create_ticket( zendesk_client.create_ticket(
subject='Request to go live - {}'.format(current_service['name']), subject='Request to go live - {}'.format(current_service.name),
message=( message=(
'Service: {}\n' 'Service: {}\n'
'{}\n' '{}\n'
@@ -212,9 +212,9 @@ def submit_request_to_go_live(service_id):
'\nPeak volume: {}' '\nPeak volume: {}'
'\nFeatures: {}' '\nFeatures: {}'
).format( ).format(
current_service['name'], current_service.name,
url_for('main.service_dashboard', service_id=current_service['id'], _external=True), url_for('main.service_dashboard', service_id=current_service.id, _external=True),
current_service['organisation_type'], current_service.organisation_type,
AgreementInfo.from_current_user().as_human_readable, AgreementInfo.from_current_user().as_human_readable,
formatted_list(filter(None, ( formatted_list(filter(None, (
'email' if form.channel_email.data else None, 'email' if form.channel_email.data else None,
@@ -246,11 +246,11 @@ def submit_request_to_go_live(service_id):
@user_is_platform_admin @user_is_platform_admin
def service_switch_live(service_id): def service_switch_live(service_id):
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
# TODO This limit should be set depending on the agreement signed by # TODO This limit should be set depending on the agreement signed by
# with Notify. # with Notify.
message_limit=250000 if current_service['restricted'] else 50, message_limit=250000 if current_service.trial_mode else 50,
restricted=(not current_service['restricted']) restricted=(not current_service.trial_mode)
) )
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
@@ -261,7 +261,7 @@ def service_switch_live(service_id):
def service_switch_research_mode(service_id): def service_switch_research_mode(service_id):
service_api_client.update_service_with_properties( service_api_client.update_service_with_properties(
service_id, service_id,
{"research_mode": not current_service['research_mode']} {"research_mode": not current_service.research_mode}
) )
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
@@ -271,14 +271,14 @@ def switch_service_permissions(service_id, permission, sms_sender=None):
force_service_permission( force_service_permission(
service_id, service_id,
permission, permission,
on=permission not in current_service['permissions'], on=permission not in current_service.permissions,
sms_sender=sms_sender sms_sender=sms_sender
) )
def force_service_permission(service_id, permission, on=False, sms_sender=None): def force_service_permission(service_id, permission, on=False, sms_sender=None):
permissions, permission = set(current_service['permissions']), {permission} permissions, permission = set(current_service.permissions), {permission}
update_service_permissions( update_service_permissions(
service_id, service_id,
@@ -289,9 +289,7 @@ def force_service_permission(service_id, permission, on=False, sms_sender=None):
def update_service_permissions(service_id, permissions, sms_sender=None): def update_service_permissions(service_id, permissions, sms_sender=None):
current_service['permissions'] = list(permissions) data = {'permissions': list(permissions)}
data = {'permissions': current_service['permissions']}
if sms_sender: if sms_sender:
data['sms_sender'] = sms_sender data['sms_sender'] = sms_sender
@@ -339,13 +337,13 @@ def service_switch_can_upload_document(service_id):
# If turning the permission off, or turning it on and the service already has a contact_link, # If turning the permission off, or turning it on and the service already has a contact_link,
# don't show the form to add the link # don't show the form to add the link
if 'upload_document' in current_service['permissions'] or current_service.get('contact_link'): if current_service.has_permission('upload_document') or current_service.get('contact_link'):
switch_service_permissions(service_id, 'upload_document') switch_service_permissions(service_id, 'upload_document')
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
contact_link=form.url.data contact_link=form.url.data
) )
switch_service_permissions(service_id, 'upload_document') switch_service_permissions(service_id, 'upload_document')
@@ -402,10 +400,10 @@ def service_set_contact_link(service_id):
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
contact_link=form.url.data contact_link=form.url.data
) )
return redirect(url_for('.service_settings', service_id=current_service['id'])) return redirect(url_for('.service_settings', service_id=current_service.id))
return render_template('views/service-settings/contact_link.html', form=form) return render_template('views/service-settings/contact_link.html', form=form)
@@ -445,7 +443,7 @@ def service_add_email_reply_to(service_id):
first_email_address = reply_to_email_address_count == 0 first_email_address = reply_to_email_address_count == 0
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.add_reply_to_email_address( service_api_client.add_reply_to_email_address(
current_service['id'], current_service.id,
email_address=form.email_address.data, email_address=form.email_address.data,
is_default=first_email_address if first_email_address else form.is_default.data is_default=first_email_address if first_email_address else form.is_default.data
) )
@@ -476,7 +474,7 @@ def service_edit_email_reply_to(service_id, reply_to_email_id):
form.is_default.data = reply_to_email_address['is_default'] form.is_default.data = reply_to_email_address['is_default']
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_reply_to_email_address( service_api_client.update_reply_to_email_address(
current_service['id'], current_service.id,
reply_to_email_id=reply_to_email_id, reply_to_email_id=reply_to_email_id,
email_address=form.email_address.data, email_address=form.email_address.data,
is_default=True if reply_to_email_address['is_default'] else form.is_default.data is_default=True if reply_to_email_address['is_default'] else form.is_default.data
@@ -495,7 +493,7 @@ def service_edit_email_reply_to(service_id, reply_to_email_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def service_delete_email_reply_to(service_id, reply_to_email_id): def service_delete_email_reply_to(service_id, reply_to_email_id):
service_api_client.delete_reply_to_email_address( service_api_client.delete_reply_to_email_address(
service_id=current_service['id'], service_id=current_service.id,
reply_to_email_id=reply_to_email_id, reply_to_email_id=reply_to_email_id,
) )
return redirect(url_for('.service_email_reply_to', service_id=service_id)) return redirect(url_for('.service_email_reply_to', service_id=service_id))
@@ -516,12 +514,12 @@ def service_set_inbound_number(service_id):
) )
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.add_sms_sender( service_api_client.add_sms_sender(
current_service['id'], current_service.id,
sms_sender=form.inbound_number.data, sms_sender=form.inbound_number.data,
is_default=True, is_default=True,
inbound_number_id=form.inbound_number.data inbound_number_id=form.inbound_number.data
) )
switch_service_permissions(current_service['id'], 'inbound_sms') switch_service_permissions(current_service.id, 'inbound_sms')
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
return render_template( return render_template(
'views/service-settings/set-inbound-number.html', 'views/service-settings/set-inbound-number.html',
@@ -546,14 +544,14 @@ def service_set_sms(service_id):
def service_set_sms_prefix(service_id): def service_set_sms_prefix(service_id):
form = SMSPrefixForm(enabled=( form = SMSPrefixForm(enabled=(
'on' if current_service['prefix_sms'] else 'off' 'on' if current_service.prefix_sms else 'off'
)) ))
form.enabled.label.text = 'Start all text messages with {}:'.format(current_service['name']) form.enabled.label.text = 'Start all text messages with {}:'.format(current_service.name)
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
prefix_sms=(form.enabled.data == 'on') prefix_sms=(form.enabled.data == 'on')
) )
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
@@ -569,7 +567,7 @@ def service_set_sms_prefix(service_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def service_set_international_sms(service_id): def service_set_international_sms(service_id):
form = InternationalSMSForm( form = InternationalSMSForm(
enabled='on' if 'international_sms' in current_service['permissions'] else 'off' enabled='on' if current_service.has_permission('international_sms') else 'off'
) )
if form.validate_on_submit(): if form.validate_on_submit():
force_service_permission( force_service_permission(
@@ -602,7 +600,7 @@ def service_set_inbound_sms(service_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def service_set_letters(service_id): def service_set_letters(service_id):
form = ServiceSwitchLettersForm( form = ServiceSwitchLettersForm(
enabled='on' if 'letter' in current_service['permissions'] else 'off' enabled='on' if current_service.has_permission('letter') else 'off'
) )
if form.validate_on_submit(): if form.validate_on_submit():
force_service_permission( force_service_permission(
@@ -640,7 +638,7 @@ def service_set_basic_view(service_id):
abort(403) abort(403)
form = ServiceBasicViewForm( form = ServiceBasicViewForm(
enabled='caseworking' in current_service['permissions'] enabled=current_service.has_permission('caseworking')
) )
if form.validate_on_submit(): if form.validate_on_submit():
force_service_permission( force_service_permission(
@@ -684,7 +682,7 @@ def service_add_letter_contact(service_id):
first_contact_block = letter_contact_blocks_count == 0 first_contact_block = letter_contact_blocks_count == 0
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.add_letter_contact( service_api_client.add_letter_contact(
current_service['id'], current_service.id,
contact_block=form.letter_contact_block.data.replace('\r', '') or None, contact_block=form.letter_contact_block.data.replace('\r', '') or None,
is_default=first_contact_block if first_contact_block else form.is_default.data is_default=first_contact_block if first_contact_block else form.is_default.data
) )
@@ -709,7 +707,7 @@ def service_edit_letter_contact(service_id, letter_contact_id):
form.is_default.data = letter_contact_block['is_default'] form.is_default.data = letter_contact_block['is_default']
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_letter_contact( service_api_client.update_letter_contact(
current_service['id'], current_service.id,
letter_contact_id=letter_contact_id, letter_contact_id=letter_contact_id,
contact_block=form.letter_contact_block.data.replace('\r', '') or None, contact_block=form.letter_contact_block.data.replace('\r', '') or None,
is_default=True if letter_contact_block['is_default'] else form.is_default.data is_default=True if letter_contact_block['is_default'] else form.is_default.data
@@ -755,7 +753,7 @@ def service_add_sms_sender(service_id):
first_sms_sender = sms_sender_count == 0 first_sms_sender = sms_sender_count == 0
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.add_sms_sender( service_api_client.add_sms_sender(
current_service['id'], current_service.id,
sms_sender=form.sms_sender.data.replace('\r', '') or None, sms_sender=form.sms_sender.data.replace('\r', '') or None,
is_default=first_sms_sender if first_sms_sender else form.is_default.data is_default=first_sms_sender if first_sms_sender else form.is_default.data
) )
@@ -788,7 +786,7 @@ def service_edit_sms_sender(service_id, sms_sender_id):
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_sms_sender( service_api_client.update_sms_sender(
current_service['id'], current_service.id,
sms_sender_id=sms_sender_id, sms_sender_id=sms_sender_id,
sms_sender=sms_sender['sms_sender'] if is_inbound_number else form.sms_sender.data.replace('\r', ''), sms_sender=sms_sender['sms_sender'] if is_inbound_number else form.sms_sender.data.replace('\r', ''),
is_default=True if sms_sender['is_default'] else form.is_default.data is_default=True if sms_sender['is_default'] else form.is_default.data
@@ -814,7 +812,7 @@ def service_edit_sms_sender(service_id, sms_sender_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def service_delete_sms_sender(service_id, sms_sender_id): def service_delete_sms_sender(service_id, sms_sender_id):
service_api_client.delete_sms_sender( service_api_client.delete_sms_sender(
service_id=current_service['id'], service_id=current_service.id,
sms_sender_id=sms_sender_id, sms_sender_id=sms_sender_id,
) )
return redirect(url_for('.service_sms_senders', service_id=service_id)) return redirect(url_for('.service_sms_senders', service_id=service_id))
@@ -825,13 +823,13 @@ def service_delete_sms_sender(service_id, sms_sender_id):
@user_has_permissions('manage_service') @user_has_permissions('manage_service')
def service_set_letter_contact_block(service_id): def service_set_letter_contact_block(service_id):
if 'letter' not in current_service['permissions']: if not current_service.has_permission('letter'):
abort(403) abort(403)
form = ServiceLetterContactBlockForm(letter_contact_block=current_service['letter_contact_block']) form = ServiceLetterContactBlockForm(letter_contact_block=current_service.letter_contact_block)
if form.validate_on_submit(): if form.validate_on_submit():
service_api_client.update_service( service_api_client.update_service(
current_service['id'], current_service.id,
letter_contact_block=form.letter_contact_block.data.replace('\r', '') or None letter_contact_block=form.letter_contact_block.data.replace('\r', '') or None
) )
if request.args.get('from_template'): if request.args.get('from_template'):
@@ -908,7 +906,7 @@ def service_set_email_branding(service_id):
) )
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
form.branding_style.data = current_service['email_branding'] or 'None' form.branding_style.data = current_service.email_branding or 'None'
return render_template( return render_template(
'views/service-settings/set-email-branding.html', 'views/service-settings/set-email-branding.html',
@@ -973,12 +971,12 @@ def link_service_to_organisation(service_id):
def branding_request(service_id): def branding_request(service_id):
form = BrandingOptionsEmail( form = BrandingOptionsEmail(
options=current_service['branding'] options=current_service.branding
) )
if form.validate_on_submit(): if form.validate_on_submit():
zendesk_client.create_ticket( zendesk_client.create_ticket(
subject='Email branding request - {}'.format(current_service['name']), subject='Email branding request - {}'.format(current_service.name),
message=( message=(
'Organisation: {}\n' 'Organisation: {}\n'
'Service: {}\n' 'Service: {}\n'
@@ -987,8 +985,8 @@ def branding_request(service_id):
'\nBranding requested: {}' '\nBranding requested: {}'
).format( ).format(
AgreementInfo.from_current_user().as_info_for_branding_request, AgreementInfo.from_current_user().as_info_for_branding_request,
current_service['name'], current_service.name,
url_for('main.service_dashboard', service_id=current_service['id'], _external=True), url_for('main.service_dashboard', service_id=current_service.id, _external=True),
branding_options_dict[form.options.data], branding_options_dict[form.options.data],
), ),
ticket_type=zendesk_client.TYPE_QUESTION, ticket_type=zendesk_client.TYPE_QUESTION,
+9 -9
View File
@@ -108,7 +108,7 @@ def choose_template(service_id, template_type='all'):
templates = service_api_client.get_service_templates(service_id)['data'] templates = service_api_client.get_service_templates(service_id)['data']
letters_available = ( letters_available = (
'letter' in current_service['permissions'] and current_service.has_permission('letter') and
current_user.has_permissions('view_activity') current_user.has_permissions('view_activity')
) )
@@ -128,7 +128,7 @@ def choose_template(service_id, template_type='all'):
}) > 1 }) > 1
template_nav_items = [ template_nav_items = [
(label, key, url_for('.choose_template', service_id=current_service['id'], template_type=key), '') (label, key, url_for('.choose_template', service_id=current_service.id, template_type=key), '')
for label, key in filter(None, [ for label, key in filter(None, [
('All', 'all'), ('All', 'all'),
('Text message', 'sms'), ('Text message', 'sms'),
@@ -207,9 +207,9 @@ def view_template_version_preview(service_id, template_id, version, filetype):
def add_template_by_type(service_id): def add_template_by_type(service_id):
form = ChooseTemplateType( form = ChooseTemplateType(
include_letters='letter' in current_service['permissions'], include_letters=current_service.has_permission('letter'),
include_copy=any(( include_copy=any((
service_api_client.count_service_templates(service_id), service_api_client.count_service_templates(service_id) > 0,
len(user_api_client.get_service_ids_for_user(current_user)) > 1, len(user_api_client.get_service_ids_for_user(current_user)) > 1,
)), )),
) )
@@ -237,7 +237,7 @@ def add_template_by_type(service_id):
template_id=blank_letter['data']['id'], template_id=blank_letter['data']['id'],
)) ))
if email_or_sms_not_enabled(form.template_type.data, current_service['permissions']): if email_or_sms_not_enabled(form.template_type.data, current_service.permissions):
return redirect(url_for( return redirect(url_for(
'.action_blocked', '.action_blocked',
service_id=service_id, service_id=service_id,
@@ -325,7 +325,7 @@ def add_service_template(service_id, template_type):
if template_type not in ['sms', 'email', 'letter']: if template_type not in ['sms', 'email', 'letter']:
abort(404) abort(404)
if 'letter' not in current_service['permissions'] and template_type == 'letter': if not current_service.has_permission('letter') and template_type == 'letter':
abort(403) abort(403)
form = form_objects[template_type]() form = form_objects[template_type]()
@@ -355,7 +355,7 @@ def add_service_template(service_id, template_type):
url_for('.view_template', service_id=service_id, template_id=new_template['data']['id']) url_for('.view_template', service_id=service_id, template_id=new_template['data']['id'])
) )
if email_or_sms_not_enabled(template_type, current_service['permissions']): if email_or_sms_not_enabled(template_type, current_service.permissions):
return redirect(url_for( return redirect(url_for(
'.action_blocked', '.action_blocked',
service_id=service_id, service_id=service_id,
@@ -444,7 +444,7 @@ def edit_service_template(service_id, template_id):
db_template = service_api_client.get_service_template(service_id, template_id)['data'] db_template = service_api_client.get_service_template(service_id, template_id)['data']
if email_or_sms_not_enabled(db_template['template_type'], current_service['permissions']): if email_or_sms_not_enabled(db_template['template_type'], current_service.permissions):
return redirect(url_for( return redirect(url_for(
'.action_blocked', '.action_blocked',
service_id=service_id, service_id=service_id,
@@ -672,5 +672,5 @@ def get_human_readable_delta(from_time, until_time):
def should_show_template(template_type): def should_show_template(template_type):
return ( return (
template_type != 'letter' or template_type != 'letter' or
'letter' in current_service['permissions'] current_service.has_permission('letter')
) )
+1 -1
View File
@@ -47,7 +47,7 @@ class NotifyAdminAPIClient(BaseAPIClient):
# if the current service is inactive and the user isn't a platform admin, we should block them from making any # if the current service is inactive and the user isn't a platform admin, we should block them from making any
# stateful modifications to that service # stateful modifications to that service
if current_service and not current_service['active'] and not current_user.platform_admin: if current_service and not current_service.active and not current_user.platform_admin:
abort(403) abort(403)
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
+37
View File
@@ -261,3 +261,40 @@ class AnonymousUser(AnonymousUserMixin):
# set the anonymous user so that if a new browser hits us we don't error http://stackoverflow.com/a/19275188 # set the anonymous user so that if a new browser hits us we don't error http://stackoverflow.com/a/19275188
def logged_in_elsewhere(self): def logged_in_elsewhere(self):
return False return False
class Service(dict):
ALLOWED_PROPERTIES = {
'active',
'branding',
'dvla_organisation',
'email_branding',
'email_from',
'id',
'inbound_api',
'letter_contact_block',
'message_limit',
'name',
'organisation_type',
'permissions',
'prefix_sms',
'research_mode',
'service_callback_api',
}
def __init__(self, _dict):
# in the case of a bad request current service may be `None`
super().__init__(_dict or {})
def __getattr__(self, attr):
if attr in self.ALLOWED_PROPERTIES:
return self[attr]
raise AttributeError
@property
def trial_mode(self):
return self['restricted']
def has_permission(self, permission):
return permission in self.permissions
+1 -1
View File
@@ -11,7 +11,7 @@ class TemplatePreview:
'letter_contact_block': template.get('reply_to_text', ''), 'letter_contact_block': template.get('reply_to_text', ''),
'template': template, 'template': template,
'values': values, 'values': values,
'dvla_org_id': current_service['dvla_organisation'], 'dvla_org_id': current_service.dvla_organisation,
} }
resp = requests.post( resp = requests.post(
'{}/preview.{}{}'.format( '{}/preview.{}{}'.format(
+1 -1
View File
@@ -111,7 +111,7 @@
Built by the <a href="https://www.gov.uk/government/organisations/government-digital-service">Government Digital Service</a> Built by the <a href="https://www.gov.uk/government/organisations/government-digital-service">Government Digital Service</a>
<a href="{{ url_for("main.privacy") }}">Privacy</a> <a href="{{ url_for("main.privacy") }}">Privacy</a>
<a href="{{ url_for("main.cookies") }}">Cookies</a> <a href="{{ url_for("main.cookies") }}">Cookies</a>
{% if current_service.research_mode %} {% if current_service and current_service.research_mode %}
<span id="research-mode" class="research-mode">research mode</span> <span id="research-mode" class="research-mode">research mode</span>
{% endif %} {% endif %}
</nav> </nav>
+1 -1
View File
@@ -27,7 +27,7 @@
smaller=smaller_font_size smaller=smaller_font_size
) }} ) }}
</div> </div>
{% if 'letter' in current_service['permissions'] %} {% if current_service.has_permission('letter') %}
<div id="total-letters" class="{{column_width}}"> <div id="total-letters" class="{{column_width}}">
{{ big_number_with_status( {{ big_number_with_status(
statistics['letter']['requested'], statistics['letter']['requested'],
+1 -1
View File
@@ -92,7 +92,7 @@
'Basic view' 'Basic view'
) }} ) }}
{% endif %} {% endif %}
{% if 'email_auth' in current_service['permissions'] %} {% if current_service.has_permission('email_auth') %}
<div class="tick-cross-list-hint"> <div class="tick-cross-list-hint">
{% if user.auth_type == 'sms_auth' %} {% if user.auth_type == 'sms_auth' %}
Signs in with a text message code Signs in with a text message code
+4 -4
View File
@@ -292,8 +292,8 @@ def get_template(
if 'email' == template['template_type']: if 'email' == template['template_type']:
return EmailPreviewTemplate( return EmailPreviewTemplate(
template, template,
from_name=service['name'], from_name=service.name,
from_address='{}@notifications.service.gov.uk'.format(service['email_from']), from_address='{}@notifications.service.gov.uk'.format(service.email_from),
expanded=expand_emails, expanded=expand_emails,
show_recipient=show_recipient, show_recipient=show_recipient,
redact_missing_personalisation=redact_missing_personalisation, redact_missing_personalisation=redact_missing_personalisation,
@@ -302,8 +302,8 @@ def get_template(
if 'sms' == template['template_type']: if 'sms' == template['template_type']:
return SMSPreviewTemplate( return SMSPreviewTemplate(
template, template,
prefix=service['name'], prefix=service.name,
show_prefix=service['prefix_sms'], show_prefix=service.prefix_sms,
sender=sms_sender, sender=sms_sender,
show_sender=bool(sms_sender), show_sender=bool(sms_sender),
show_recipient=show_recipient, show_recipient=show_recipient,
+3 -1
View File
@@ -487,6 +487,7 @@ def test_should_validate_whitelist_items(
def test_callback_forms_validation( def test_callback_forms_validation(
client_request, client_request,
service_one, service_one,
mock_get_valid_service_callback_api,
endpoint, endpoint,
url, url,
bearer_token, bearer_token,
@@ -606,7 +607,8 @@ def test_callbacks_button_links_straight_to_delivery_status_if_service_has_no_in
def test_callbacks_page_redirects_to_delivery_status_if_service_has_no_inbound_sms( def test_callbacks_page_redirects_to_delivery_status_if_service_has_no_inbound_sms(
client_request, client_request,
service_one, service_one,
mocker mocker,
mock_get_valid_service_callback_api,
): ):
page = client_request.get( page = client_request.get(
'main.api_callbacks', 'main.api_callbacks',
@@ -2039,8 +2039,10 @@ def test_service_switch_can_upload_document_changes_the_permission_if_not_adding
follow_redirects=True follow_redirects=True
) )
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
mock_update_service.assert_called_once_with(
assert service_one['permissions'] == end_permissions SERVICE_ONE_ID,
permissions=end_permissions,
)
assert page.h1.text.strip() == 'Settings' assert page.h1.text.strip() == 'Settings'
@@ -2080,7 +2082,7 @@ def test_service_switch_can_upload_document_lets_contact_link_be_added_and_switc
) )
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert 'upload_document' in service_one['permissions'] assert 'upload_document' in mock_update_service.call_args[1]['permissions']
assert page.h1.text.strip() == 'Settings' assert page.h1.text.strip() == 'Settings'
+1 -1
View File
@@ -49,7 +49,7 @@ def test_from_database_object_makes_request(
): ):
resp = Mock(content='a', status_code='b', headers={'c': 'd'}) resp = Mock(content='a', status_code='b', headers={'c': 'd'})
request_mock = mocker.patch('app.template_previews.requests.post', return_value=resp) request_mock = mocker.patch('app.template_previews.requests.post', return_value=resp)
mocker.patch('app.template_previews.current_service', __getitem__=Mock(return_value='123')) mocker.patch('app.template_previews.current_service', dvla_organisation='123')
template = mock_get_service_letter_template('123', '456')['data'] template = mock_get_service_letter_template('123', '456')['data']
ret = partial_call(template=template) ret = partial_call(template=template)