Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add admin interfact to suspend callback if they exist #1937

Merged
merged 3 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/main/views/service_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,18 @@ def service_settings(service_id: str):
"free_yearly_email": current_app.config["FREE_YEARLY_EMAIL_LIMIT"],
"free_yearly_sms": current_app.config["FREE_YEARLY_SMS_LIMIT"],
}
callback_api = (
service_api_client.get_service_callback_api(current_service.id, current_service.service_callback_api[0])
if current_service.service_callback_api
else None
)
assert limits["free_yearly_email"] >= 2_000_000, "The user-interface does not support French translations of < 2M"
return render_template(
"views/service-settings.html",
service_permissions=PLATFORM_ADMIN_SERVICE_PERMISSIONS,
sending_domain=current_service.sending_domain or current_app.config["SENDING_DOMAIN"], # type: ignore
limits=limits,
callback_api=callback_api,
)


Expand Down Expand Up @@ -1458,6 +1464,37 @@ def edit_data_retention(service_id, data_retention_id):
)


@main.route(
"/services/<service_id>/service-settings/suspend-callback",
methods=["GET", "POST"],
)
@user_is_platform_admin
def suspend_callback(service_id):
title = _("Suspend Callback")
form = ServiceOnOffSettingForm(name=title)
if current_service.service_callback_api:
callback_api = service_api_client.get_service_callback_api(current_service.id, current_service.service_callback_api[0])
form = ServiceOnOffSettingForm(name=title, enabled=callback_api["is_suspended"])

if form.validate_on_submit():
try:
service_api_client.suspend_service_callback_api(service_id, current_user.id, suspend_unsuspend=form.enabled.data)
except Exception as e:
raise "Error suspending callback: {}".format(e)
return redirect(url_for(".service_settings", service_id=service_id))

return render_template(
"views/service-settings/set-service-setting.html",
title=_("Suspend Callback"),
form=form,
)
return render_template(
"views/service-settings/set-service-setting.html",
title=_("Suspend Callback"),
form=form,
)


def get_branding_as_value_and_label(email_branding):
return [(branding["id"], branding["name"]) for branding in email_branding]

Expand Down
3 changes: 3 additions & 0 deletions app/models/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def update_permissions(self, permissions):
def toggle_research_mode(self):
self.update(research_mode=not self.research_mode)

def suspend_callback_api(self, **kwargs):
return service_api_client.suspend_service_callback_api(self.id, **kwargs)

@property
def trial_mode(self):
return self._dict["restricted"]
Expand Down
2 changes: 1 addition & 1 deletion app/notify_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
if current_service:
service_is_sensitive = current_service.sensitive_service if current_service.sensitive_service else False
if hasattr(current_user, "platform_admin") and current_user.platform_admin:
user = current_user.email_address + "|" + current_user.id
user = f"{current_user.email_address}|{current_user.id}"
logger.warn("{}Admin API request {} {} {} ".format("Sensitive " if service_is_sensitive else "", method, url, user))

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
This log entry depends on a [user-p

def get(self, url, params=None):
if (
Expand Down
7 changes: 7 additions & 0 deletions app/notify_client/service_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,13 @@ def update_service_callback_api(self, service_id, url, bearer_token, user_id, ca
def delete_service_callback_api(self, service_id, callback_api_id):
return self.delete("/service/{}/delivery-receipt-api/{}".format(service_id, callback_api_id))

@cache.delete("service-{service_id}")
def suspend_service_callback_api(self, service_id, updated_by_id, suspend_unsuspend):
return self.post(
"/service/{}/delivery-receipt-api/suspend-callback".format(service_id),
data={"updated_by_id": updated_by_id, "suspend_unsuspend": suspend_unsuspend},
)

@cache.delete("service-{service_id}")
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}
Expand Down
19 changes: 19 additions & 0 deletions app/templates/views/service-settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,25 @@ <h2 class="heading-medium">{{ _('Platform admin settings') }}</h2>
) }}
{% endcall %}

{%if callback_api%}
{% call row() %}
{% set txt = _('Suspend Callback') %}
{{ text_field(txt)}}
{% if callback_api is not none and callback_api.is_suspended %}
{% set value = _('On') %}
{{ text_field(value) }}
{% else %}
{% set value = _('Off') %}
{{ text_field(value) }}
{% endif %}
{{ edit_field(
change_txt,
url_for('.suspend_callback', service_id=current_service.id),
for=txt
) }}
{% endcall %}
{% endif %}

{% endcall %}

</div>
Expand Down
1 change: 1 addition & 0 deletions app/translations/csv/fr.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1977,3 +1977,4 @@
"Change your filters or search for more templates","Modifiez vos filtres ou recherchez d’autres gabarits"
"Review your activity","Examinez votre activité"
"Set sensitive service","Définir un service sensible"
"Suspend Callback","Suspension du rappel"
12 changes: 12 additions & 0 deletions tests/app/main/views/test_service_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4306,3 +4306,15 @@ def test_should_redirect_after_change_service_name(
client_request.post(
"main.set_sensitive_service", service_id=SERVICE_ONE_ID, _data={"sensitive_service": False}, _expected_status=200
)


class TestSuspendingCallbackApi:
def test_should_suspend_service_callback_api(self, client_request, platform_admin_user, mocker, service_one):

client_request.login(platform_admin_user, service_one)
client_request.post(
"main.suspend_callback",
service_id=service_one["id"],
_data={"updated_by_id": platform_admin_user["id"], "suspend_unsuspend": False},
_expected_status=200,
)
13 changes: 13 additions & 0 deletions tests/app/notify_client/test_service_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,3 +576,16 @@ def test_store_use_case_data(mocker):
ex=60 * 60 * 60 * 24, # 60 days in seconds
)
mock_redis_delete.assert_called_once_with(f"use-case-submitted-{SERVICE_ONE_ID}")


class TestSuspendCallbackApi:
def test_suspend_callback_api(self, mocker, active_user_with_permissions):
service_id = str(uuid4())
mock_post = mocker.patch("app.notify_client.service_api_client.ServiceAPIClient.post")
ServiceAPIClient().suspend_service_callback_api(service_id, active_user_with_permissions["id"], True)
mock_post.assert_called_once()
args, kwargs = mock_post.call_args_list[0]
expected_url = f"/service/{service_id}/delivery-receipt-api/suspend-callback"
expected_data = {"updated_by_id": active_user_with_permissions["id"], "suspend_unsuspend": True}
assert args[0] == expected_url
assert kwargs["data"] == expected_data
Loading