diff --git a/.envs/sample.env b/.envs/sample.env index 10bb6c1c34..3380015d29 100644 --- a/.envs/sample.env +++ b/.envs/sample.env @@ -78,16 +78,15 @@ S3_POLICY_DOCUMENT_TEMPLATE_BASE64=e30= S3_PERMISSIONS_BOUNDARY_ARN=my-arn S3_ROLE_PREFIX=my-prefix -ZENDESK_EMAIL=test@test.com -# ZENDESK_SUBDOMAIN just requires the subdomain part not the full url -# i.e. for subdomain.zendesk.com the value should be subdomain -ZENDESK_SUBDOMAIN=subdomain -ZENDESK_TOKEN=abcd - -# ZENDESK_SERVICE_FIELD_ID is a numeric value for a custom field within zendesk which is -# set to the ZENDESK_SERVIE_FIELD_VALUE when requesting access to datasets zendesk.py -ZENDESK_SERVICE_FIELD_ID=numeric_field_id -ZENDESK_SERVICE_FIELD_VALUE=field_value +# HELP_DESK_SERVICE_FIELD_ID is a numeric value for a custom field within the help desk which is +# set to the HELPDESK_SERVICE_FIELD_VALUE when requesting access to datasets help_desk.py +HELP_DESK_EMAIL=test@test.com +HELP_DESK_SERVICE_FIELD_ID=numeric_field_id +HELP_DESK_SERVICE_FIELD_VALUE=field_value + +# helpdesk abstraction +HELP_DESK_INTERFACE=helpdesk_client.interfaces.HelpDeskStubbed +HELP_DESK_CREDS=xxx NOTIFY_API_KEY=notify-token FERNET_EMAIL_TOKEN_KEY=generate-using-fernet-generate-key diff --git a/.envs/test.env b/.envs/test.env index f21ff488d1..759cdb4be8 100644 --- a/.envs/test.env +++ b/.envs/test.env @@ -54,11 +54,9 @@ AWS_ECR_ENDPOINT_URL=http://api.ecr.my-region-1.amazonaws.com:8008/ PROMETHEUS_DOMAIN=some.domain.com METRICS_SERVICE_DISCOVERY_BASIC_AUTH_USER=user METRICS_SERVICE_DISCOVERY_BASIC_AUTH_PASSWORD=password -ZENDESK_EMAIL=test@test.com -ZENDESK_SUBDOMAIN=subdomain -ZENDESK_TOKEN=abcd -ZENDESK_SERVICE_FIELD_ID=654321 -ZENDESK_SERVICE_FIELD_VALUE=field_value +HELP_DESK_EMAIL=test@test.com +HELP_DESK_SERVICE_FIELD_ID=654321 +HELP_DESK_SERVICE_FIELD_VALUE=field_value S3_ASSUME_ROLE_POLICY_DOCUMENT_BASE64=e30= S3_POLICY_NAME=my-policy S3_POLICY_DOCUMENT_TEMPLATE_BASE64=e30= @@ -67,6 +65,9 @@ S3_ROLE_PREFIX=my-prefix ALLOWED_HOSTS='dataworkspace.test' +HELP_DESK_INTERFACE=helpdesk_client.interfaces.HelpDeskStubbed + + UPLOADS_BUCKET=an-upload-bucket MIRROR_REMOTE_ROOT=http://127.0.0.1:8006/some-remote-folder/ diff --git a/Makefile b/Makefile index 0dde95418a..75eb23c6e3 100644 --- a/Makefile +++ b/Makefile @@ -37,8 +37,7 @@ docker-test-unit: docker-build .PHONY: docker-test-integration docker-test-integration: docker-build - docker-compose -f docker-compose-test.yml -p data-workspace-test run data-workspace-test pytest test/ - + docker-compose -f docker-compose-test.yml -p data-workspace-test run -e DJANGO_SETTINGS_MODULE=dataworkspace.settings.integration_tests data-workspace-test pytest test/ .PHONY: docker-test docker-test: docker-test-integration docker-test-unit diff --git a/dataworkspace/dataworkspace/apps/applications/views.py b/dataworkspace/dataworkspace/apps/applications/views.py index 148763c055..d83b246f0e 100644 --- a/dataworkspace/dataworkspace/apps/applications/views.py +++ b/dataworkspace/dataworkspace/apps/applications/views.py @@ -83,7 +83,7 @@ from dataworkspace.apps.eventlog.models import EventLog from dataworkspace.apps.eventlog.utils import log_event from dataworkspace.notify import decrypt_token, send_email -from dataworkspace.zendesk import update_zendesk_ticket +from dataworkspace.help_desk import update_helpdesk_ticket TOOL_LOADING_MESSAGES = [ { @@ -726,7 +726,7 @@ def error(email_address_error): return error(f"{user.get_full_name()} already has access") if email_address == token_data.get("email", "").strip().lower(): - update_zendesk_ticket( + update_helpdesk_ticket( token_data["ticket"], comment=f"Access granted by {request.user.email}", status="solved", diff --git a/dataworkspace/dataworkspace/apps/core/views.py b/dataworkspace/dataworkspace/apps/core/views.py index 7567604cc3..47c68a5e2b 100644 --- a/dataworkspace/dataworkspace/apps/core/views.py +++ b/dataworkspace/dataworkspace/apps/core/views.py @@ -43,7 +43,7 @@ ) from dataworkspace.apps.eventlog.models import EventLog from dataworkspace.apps.eventlog.utils import log_event -from dataworkspace.zendesk import create_support_request +from dataworkspace.help_desk import create_support_request logger = logging.getLogger("app") @@ -101,7 +101,7 @@ class SupportView(FormView): form_class = SupportForm template_name = "core/support.html" - ZENDESK_TAGS = {"data-request": "data_request"} + HELP_DESK_TAGS = {"data-request": "data_request"} def get_context_data(self, **kwargs): ctx = super().get_context_data() @@ -122,7 +122,7 @@ def form_valid(self, form): if cleaned["support_type"] == form.SupportTypes.TECH_SUPPORT: return HttpResponseRedirect(f'{reverse("technical-support")}?email={cleaned["email"]}') - tag = self.ZENDESK_TAGS.get(self.request.GET.get("tag")) + tag = self.HELP_DESK_TAGS.get(self.request.GET.get("tag")) ticket_id = create_support_request( self.request.user, cleaned["email"], cleaned["message"], tag=tag ) diff --git a/dataworkspace/dataworkspace/apps/request_access/migrations/0005_rename_zendesk_reference_number_accessrequest.py b/dataworkspace/dataworkspace/apps/request_access/migrations/0005_rename_zendesk_reference_number_accessrequest.py new file mode 100644 index 0000000000..be1b8bee03 --- /dev/null +++ b/dataworkspace/dataworkspace/apps/request_access/migrations/0005_rename_zendesk_reference_number_accessrequest.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.15 on 2022-09-26 17:38 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("request_access", "0004_alter_accessrequest_training_screenshot"), + ] + + operations = [ + migrations.RenameField( + model_name="accessrequest", + old_name="zendesk_reference_number", + new_name="help_desk_reference_number", + ), + ] diff --git a/dataworkspace/dataworkspace/apps/request_access/models.py b/dataworkspace/dataworkspace/apps/request_access/models.py index 318b94aa43..d0b263f8b9 100644 --- a/dataworkspace/dataworkspace/apps/request_access/models.py +++ b/dataworkspace/dataworkspace/apps/request_access/models.py @@ -31,10 +31,10 @@ class AccessRequest(TimeStampedModel): spss_and_stata = models.BooleanField(default=False, blank=True) line_manager_email_address = models.CharField(max_length=256, null=True) reason_for_spss_and_stata = models.TextField(null=True) - zendesk_reference_number = models.CharField(max_length=256, null=True) + help_desk_reference_number = models.CharField(max_length=256, null=True) def __str__(self): - return f"{self.requester} - Zendesk reference number: {self.zendesk_reference_number}" + return f"{self.requester} - Help desk reference number: {self.help_desk_reference_number}" @property def journey(self): diff --git a/dataworkspace/dataworkspace/apps/request_access/views.py b/dataworkspace/dataworkspace/apps/request_access/views.py index 2538052d8e..6712ea7b43 100644 --- a/dataworkspace/dataworkspace/apps/request_access/views.py +++ b/dataworkspace/dataworkspace/apps/request_access/views.py @@ -18,7 +18,7 @@ ) from dataworkspace.apps.request_access import models -from dataworkspace import zendesk +from dataworkspace import help_desk class DatasetAccessRequest(CreateView): @@ -173,7 +173,7 @@ class AccessRequestConfirmationPage(RequestAccessMixin, DetailView): def get(self, request, *args, **kwargs): access_request = self.get_object() - if not access_request.zendesk_reference_number: + if not access_request.help_desk_reference_number: catalogue_item = ( find_dataset(access_request.catalogue_item_id, self.request.user) if access_request.catalogue_item_id @@ -184,15 +184,15 @@ def get(self, request, *args, **kwargs): isinstance(catalogue_item, VisualisationCatalogueItem) and catalogue_item.visualisation_template is not None ): - access_request.zendesk_reference_number = ( - zendesk.notify_visualisation_access_request( + access_request.help_desk_reference_number = ( + help_desk.notify_visualisation_access_request( request, access_request, catalogue_item, ) ) else: - access_request.zendesk_reference_number = zendesk.create_zendesk_ticket( + access_request.help_desk_reference_number = help_desk.create_help_desk_ticket( request, access_request, catalogue_item, @@ -205,7 +205,7 @@ def get(self, request, *args, **kwargs): EventLog.TYPE_DATASET_ACCESS_REQUEST, catalogue_item, extra={ - "ticket_reference": access_request.zendesk_reference_number, + "ticket_reference": access_request.help_desk_reference_number, }, ) else: @@ -213,7 +213,7 @@ def get(self, request, *args, **kwargs): request.user, EventLog.TYPE_TOOLS_ACCESS_REQUEST, extra={ - "ticket_reference": access_request.zendesk_reference_number, + "ticket_reference": access_request.help_desk_reference_number, }, ) return super().get(request, *args, **kwargs) diff --git a/dataworkspace/dataworkspace/apps/request_data/migrations/0005_rename_zendesk_ticket_id_datarequest_help_desk.py b/dataworkspace/dataworkspace/apps/request_data/migrations/0005_rename_zendesk_ticket_id_datarequest_help_desk.py new file mode 100644 index 0000000000..a0fc84a8d1 --- /dev/null +++ b/dataworkspace/dataworkspace/apps/request_data/migrations/0005_rename_zendesk_ticket_id_datarequest_help_desk.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.15 on 2022-09-26 17:38 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("request_data", "0004_datarequest_data_licence"), + ] + + operations = [ + migrations.RenameField( + model_name="datarequest", + old_name="zendesk_ticket_id", + new_name="help_desk_ticket_id", + ), + ] diff --git a/dataworkspace/dataworkspace/apps/request_data/models.py b/dataworkspace/dataworkspace/apps/request_data/models.py index 1d1a0a95e2..d2f12a9519 100644 --- a/dataworkspace/dataworkspace/apps/request_data/models.py +++ b/dataworkspace/dataworkspace/apps/request_data/models.py @@ -47,4 +47,4 @@ class DataRequest(TimeStampedModel): choices=DataRequestStatus.choices, default=DataRequestStatus.draft, ) - zendesk_ticket_id = models.CharField(max_length=256) + help_desk_ticket_id = models.CharField(max_length=256) diff --git a/dataworkspace/dataworkspace/apps/request_data/views.py b/dataworkspace/dataworkspace/apps/request_data/views.py index 0a8f56d6a2..a7bf496689 100644 --- a/dataworkspace/dataworkspace/apps/request_data/views.py +++ b/dataworkspace/dataworkspace/apps/request_data/views.py @@ -17,7 +17,7 @@ RoleType, DataRequestStatus, ) -from dataworkspace.zendesk import create_support_request # pylint: disable=import-error +from dataworkspace.help_desk import create_support_request # pylint: disable=import-error class RequestData(TemplateView): @@ -249,11 +249,11 @@ def post(self, request, *args, **kwargs): # If they've hacked the URL, some required fields might be blank. try: - obj.clean_fields(exclude=["zendesk_ticket_id"]) + obj.clean_fields(exclude=["help_desk_ticket_id"]) except ValidationError: return HttpResponseBadRequest() - zendesk_message = f""" + help_desk_message = f""" A request for a new dataset on Data Workspace has been submitted. Here are the details: # Request details @@ -288,16 +288,21 @@ def post(self, request, *args, **kwargs): {obj.requester.email} """ + from django.conf import settings + + print("settings:::", flush=True) + print(settings.HELP_DESK_INTERFACE, flush=True) + ticket_id = create_support_request( obj.requester, obj.requester.email, - zendesk_message, + help_desk_message, tag="request-for-data", subject="Request for new dataset on Data Workspace", ) obj.status = DataRequestStatus.submitted - obj.zendesk_ticket_id = ticket_id + obj.help_desk_ticket_id = ticket_id obj.save() return HttpResponseRedirect( diff --git a/dataworkspace/dataworkspace/context_processors.py b/dataworkspace/dataworkspace/context_processors.py index cd0da65be7..aaa143e3b3 100644 --- a/dataworkspace/dataworkspace/context_processors.py +++ b/dataworkspace/dataworkspace/context_processors.py @@ -31,7 +31,7 @@ def common(request): "NOTIFY_ON_MASTER_DATASET_CHANGE_FLAG": settings.NOTIFY_ON_MASTER_DATASET_CHANGE_FLAG, "NOTIFY_ON_DATACUT_CHANGE_FLAG": settings.NOTIFY_ON_DATACUT_CHANGE_FLAG, "NOTIFY_ON_REFERENCE_DATASET_CHANGE_FLAG": settings.NOTIFY_ON_REFERENCE_DATASET_CHANGE_FLAG, - "ZENDESK_EMAIL": settings.ZENDESK_EMAIL, + "HELP_DESK_EMAIL": settings.HELP_DESK_EMAIL, "TEAMS_DATA_WORKSPACE_COMMUNITY_URL": settings.TEAMS_DATA_WORKSPACE_COMMUNITY_URL, "DATA_WORKSPACE_ROADMAP_URL": settings.DATA_WORKSPACE_ROADMAP_URL, "SSO_USER_ID": request.META.get("HTTP_SSO_PROFILE_USER_ID", ""), diff --git a/dataworkspace/dataworkspace/zendesk.py b/dataworkspace/dataworkspace/help_desk.py similarity index 73% rename from dataworkspace/dataworkspace/zendesk.py rename to dataworkspace/dataworkspace/help_desk.py index 06bea9f231..08e671c922 100644 --- a/dataworkspace/dataworkspace/zendesk.py +++ b/dataworkspace/dataworkspace/help_desk.py @@ -3,15 +3,21 @@ from django.conf import settings from django.urls import reverse -from zenpy import Zenpy -from zenpy.lib.api_objects import Ticket, User, Comment, CustomField + +from helpdesk_client import get_helpdesk_interface +from helpdesk_client.interfaces import ( + HelpDeskComment, + HelpDeskCustomField, + HelpDeskTicket, + HelpDeskUser, +) from dataworkspace.notify import generate_token, send_email logger = logging.getLogger("app") -zendesk_service_field_id = settings.ZENDESK_SERVICE_FIELD_ID -zendesk_service_field_value = settings.ZENDESK_SERVICE_FIELD_VALUE +help_desk_service_field_id = settings.HELP_DESK_SERVICE_FIELD_ID +help_desk_service_field_value = settings.HELP_DESK_SERVICE_FIELD_VALUE def get_username(user): @@ -72,13 +78,12 @@ def build_private_comment_text(catalogue_item, approval_url): return private_comment -def create_zendesk_ticket(request, access_request, catalogue_item=None): - client = Zenpy( - subdomain=settings.ZENDESK_SUBDOMAIN, - email=settings.ZENDESK_EMAIL, - token=settings.ZENDESK_TOKEN, - ) +# configure and instantiate the client +helpdesk_interface = get_helpdesk_interface(settings.HELP_DESK_INTERFACE) +helpdesk = helpdesk_interface(credentials=settings.HELP_DESK_CREDS) + +def create_help_desk_ticket(request, access_request, catalogue_item=None): access_request_url = request.build_absolute_uri( reverse("admin:request_access_accessrequest_change", args=(access_request.id,)) ) @@ -99,39 +104,31 @@ def create_zendesk_ticket(request, access_request, catalogue_item=None): subject = f"Access Request for {catalogue_item if catalogue_item else username}" - ticket_audit = client.tickets.create( - Ticket( - subject=subject, - description=ticket_description, - requester=User(email=access_request.requester.email, name=username), - custom_fields=[ - CustomField(id=zendesk_service_field_id, value=zendesk_service_field_value) - ], - ) + helpdesk_ticket = HelpDeskTicket( + subject=subject, + description=ticket_description, + user=HelpDeskUser(full_name=username, email=access_request.requester.email), + custom_fields=[ + HelpDeskCustomField(id=help_desk_service_field_id, value=help_desk_service_field_value) + ], + comment=HelpDeskComment(body=private_comment, public=False), ) - ticket_audit.ticket.comment = Comment(body=private_comment, public=False) - client.tickets.update(ticket_audit.ticket) + ticket_audit = helpdesk.create_ticket(helpdesk_ticket) - return ticket_audit.ticket.id + return ticket_audit.id -def update_zendesk_ticket(ticket_id, comment=None, status=None): - client = Zenpy( - subdomain=settings.ZENDESK_SUBDOMAIN, - email=settings.ZENDESK_EMAIL, - token=settings.ZENDESK_TOKEN, - ) - - ticket = client.tickets(id=ticket_id) - +def update_helpdesk_ticket(ticket_id, comment=None, status=None): if comment: - ticket.comment = Comment(body=comment, public=False) + helpdesk.helpdesk.add_comment( + ticket_id=ticket_id, comment=HelpDeskComment(body=comment, public=False) + ) if status: + ticket = helpdesk.get_ticket(ticket_id=ticket_id) ticket.status = status - - client.tickets.update(ticket) + ticket = helpdesk.update_ticket(ticket=ticket) return ticket @@ -155,7 +152,7 @@ def notify_visualisation_access_request(request, access_request, dataset): Secondary contact: {dataset.secondary_enquiries_contact.email if dataset.secondary_enquiries_contact else 'Not set'} -If access has not been granted to the requestor within 5 working days, this will trigger an update to this Zendesk ticket to resolve the request. +If access has not been granted to the requestor within 5 working days, this will trigger an update to this help desk ticket to resolve the request. """ ticket_reference = create_support_request( @@ -200,20 +197,21 @@ def notify_visualisation_access_request(request, access_request, dataset): def create_support_request(user, email, message, tag=None, subject=None): - client = Zenpy( - subdomain=settings.ZENDESK_SUBDOMAIN, - email=settings.ZENDESK_EMAIL, - token=settings.ZENDESK_TOKEN, - ) - ticket_audit = client.tickets.create( - Ticket( + ticket_audit = helpdesk.create_ticket( + HelpDeskTicket( subject=subject or "Data Workspace Support Request", description=message, - requester=User(email=email, name=user.get_full_name()), - tags=[tag] if tag else None, + user=HelpDeskUser( + full_name=user.get_full_name(), + email=email, + ), custom_fields=[ - CustomField(id=zendesk_service_field_id, value=zendesk_service_field_value) + HelpDeskCustomField( + id=help_desk_service_field_id, value=help_desk_service_field_value + ) ], + tags=[tag] if tag else None, ) ) - return ticket_audit.ticket.id + + return ticket_audit.id diff --git a/dataworkspace/dataworkspace/settings/base.py b/dataworkspace/dataworkspace/settings/base.py index f0aa98f365..886c41fe89 100644 --- a/dataworkspace/dataworkspace/settings/base.py +++ b/dataworkspace/dataworkspace/settings/base.py @@ -282,14 +282,13 @@ def aws_fargate_private_ip(): f"ws://{APPLICATION_ROOT_DOMAIN.split(':')[0]}:3000", ] +HELP_DESK_EMAIL = env.get("HELP_DESK_INTERFACE", "") +HELP_DESK_SERVICE_FIELD_ID = env.get("HELP_DESK_SERVICE_FIELD_ID", "") +HELP_DESK_SERVICE_FIELD_VALUE = env.get("HELP_DESK_SERVICE_FIELD_VALUE", "") -ZENDESK_EMAIL = env["ZENDESK_EMAIL"] -ZENDESK_SUBDOMAIN = env["ZENDESK_SUBDOMAIN"] -ZENDESK_TOKEN = env["ZENDESK_TOKEN"] - -ZENDESK_SERVICE_FIELD_ID = env["ZENDESK_SERVICE_FIELD_ID"] -ZENDESK_SERVICE_FIELD_VALUE = env["ZENDESK_SERVICE_FIELD_VALUE"] - +# helpdesk abstraction +HELP_DESK_INTERFACE = env.get("HELP_DESK_INTERFACE", "") +HELP_DESK_CREDS = env.get("HELP_DESK_CREDS", "") NOTIFY_API_KEY = env["NOTIFY_API_KEY"] FERNET_EMAIL_TOKEN_KEY = env["FERNET_EMAIL_TOKEN_KEY"] diff --git a/dataworkspace/dataworkspace/settings/integration_tests.py b/dataworkspace/dataworkspace/settings/integration_tests.py index 3a07468615..728b4107b5 100644 --- a/dataworkspace/dataworkspace/settings/integration_tests.py +++ b/dataworkspace/dataworkspace/settings/integration_tests.py @@ -2,7 +2,15 @@ from .base import * # noqa -DEBUG = True +from helpdesk_client.interfaces import ( + HelpDeskBase, + HelpDeskComment, + HelpDeskUser, + HelpDeskTicket, +) + +import requests + LOGGING = { "version": 1, @@ -19,3 +27,46 @@ "celery": {"handlers": ["dev"], "level": "INFO", "propagate": False}, }, } + + +class HelpDeskTest(HelpDeskBase): + def __init__(self, *args, **kwargs) -> None: + self._ticket_id = 1234567890987654321 + + def get_or_create_user(self, user: HelpDeskUser) -> HelpDeskUser: + raise NotImplementedError + + def create_ticket(self, ticket: HelpDeskTicket) -> HelpDeskTicket: + # Call help desk test server with ticket details + ticket.id = self._ticket_id + + requests.post( + "http://dataworkspace.test:8006/api/v2/tickets.json", + json={ + "ticket": { + "id": ticket.id, + "subject": ticket.subject, + "description": ticket.description, + "status": "new", + "requester_id": 1, + "submitter_id": 1, + }, + }, + ) + + return ticket + + def get_ticket(self, ticket_id: int) -> HelpDeskTicket: + raise NotImplementedError + + def close_ticket(self, ticket_id: int) -> HelpDeskTicket: + raise NotImplementedError + + def add_comment(self, ticket_id: int, comment: HelpDeskComment) -> HelpDeskTicket: + raise NotImplementedError + + def update_ticket(self, ticket: HelpDeskTicket) -> HelpDeskTicket: + raise NotImplementedError + + +HELP_DESK_INTERFACE = "dataworkspace.settings.integration_tests.HelpDeskTest" diff --git a/dataworkspace/dataworkspace/templates/datasets/subscriptions/unsubscribe_confirm.html b/dataworkspace/dataworkspace/templates/datasets/subscriptions/unsubscribe_confirm.html index 835ca7ffdf..a457fbfbdf 100644 --- a/dataworkspace/dataworkspace/templates/datasets/subscriptions/unsubscribe_confirm.html +++ b/dataworkspace/dataworkspace/templates/datasets/subscriptions/unsubscribe_confirm.html @@ -59,7 +59,7 @@

What happens next

If you have any questions, contact {{ ZENDESK_EMAIL }}. + href="mailto:{{ HELP_DESK_EMAIL }}">{{ HELP_DESK_EMAIL }}.

diff --git a/dataworkspace/dataworkspace/templates/request_access/confirmation-page.html b/dataworkspace/dataworkspace/templates/request_access/confirmation-page.html index 81d50c451a..e67169c0c7 100644 --- a/dataworkspace/dataworkspace/templates/request_access/confirmation-page.html +++ b/dataworkspace/dataworkspace/templates/request_access/confirmation-page.html @@ -19,7 +19,7 @@

Request complete

- Your reference number
{{ object.zendesk_reference_number }} + Your reference number
{{ object.help_desk_reference_number }}
diff --git a/dataworkspace/dataworkspace/templates/request_data/confirmation-page.html b/dataworkspace/dataworkspace/templates/request_data/confirmation-page.html index 9baa36216f..fb799f53a5 100644 --- a/dataworkspace/dataworkspace/templates/request_data/confirmation-page.html +++ b/dataworkspace/dataworkspace/templates/request_data/confirmation-page.html @@ -23,7 +23,7 @@

Application complete

- Your reference number is
{{ object.zendesk_ticket_id }} + Your reference number is
{{ object.help_desk_ticket_id }}
diff --git a/dataworkspace/dataworkspace/tests/request_access/test_views.py b/dataworkspace/dataworkspace/tests/request_access/test_views.py index 700bd68afd..52e719b58d 100644 --- a/dataworkspace/dataworkspace/tests/request_access/test_views.py +++ b/dataworkspace/dataworkspace/tests/request_access/test_views.py @@ -90,20 +90,22 @@ def test_user_redirected_to_confirmation_page_after_form_submission( ) @pytest.mark.django_db - @mock.patch("dataworkspace.apps.request_access.views.zendesk.Zenpy") + @mock.patch("dataworkspace.apps.request_access.views.help_desk.helpdesk.create_ticket") @mock.patch("dataworkspace.apps.core.storage._upload_to_clamav") - def test_zendesk_ticket_created_after_form_submission( - self, mock_upload_to_clamav, mock_zendesk_client, client, user, metadata_db + def test_helpdesk_ticket_created_after_form_submission( + self, + mock_upload_to_clamav, + mock_helpdesk_create_ticket, + client, + user, + metadata_db, ): class MockTicket: @property - def ticket(self): - return type("ticket", (object,), {"id": 1})() + def id(self): + return 1 - mock_zenpy_client = mock.MagicMock() - mock_zenpy_client.tickets.create.return_value = MockTicket() - - mock_zendesk_client.return_value = mock_zenpy_client + mock_helpdesk_create_ticket.return_value = MockTicket() mock_upload_to_clamav.return_value = ClamAVResponse({"malware": False}) @@ -136,8 +138,8 @@ def ticket(self): follow=True, ) - assert len(mock_zenpy_client.tickets.create.call_args_list) == 1 - call_args, _ = mock_zenpy_client.tickets.create.call_args_list[0] + assert len(mock_helpdesk_create_ticket.call_args_list) == 1 + call_args, _ = mock_helpdesk_create_ticket.call_args_list[0] ticket = call_args[0] assert ticket.subject == "Access Request for A master" @@ -283,17 +285,17 @@ def test_user_redirected_to_summary_page_after_step_3_form_submission( "request_access:summary-page", kwargs={"pk": access_requests[0].pk} ) - @pytest.mark.django_db + @pytest.mark.django_db() @pytest.mark.parametrize( "access_type", (UserAccessType.REQUIRES_AUTHENTICATION, UserAccessType.OPEN) ) @mock.patch("dataworkspace.apps.core.boto3_client.boto3.client") - @mock.patch("dataworkspace.apps.request_access.views.zendesk.Zenpy") + @mock.patch("dataworkspace.apps.request_access.views.help_desk.helpdesk.create_ticket") @mock.patch("dataworkspace.apps.core.storage._upload_to_clamav") - def test_zendesk_ticket_created_after_form_submission( + def test_helpdesk_ticket_created_after_form_submission( self, mock_upload_to_clamav, - mock_zendesk_client, + mock_helpdesk_create_ticket, mock_boto, client, metadata_db, @@ -301,17 +303,15 @@ def test_zendesk_ticket_created_after_form_submission( ): class MockTicket: @property - def ticket(self): - return type("ticket", (object,), {"id": 1})() + def id(self): + return 1 - mock_zenpy_client = mock.MagicMock() - mock_zenpy_client.tickets.create.return_value = MockTicket() - - mock_zendesk_client.return_value = mock_zenpy_client + mock_helpdesk_create_ticket.return_value = MockTicket() mock_upload_to_clamav.return_value = ClamAVResponse({"malware": False}) dataset = DatasetsCommon()._create_master(user_access_type=access_type) + client.get(reverse("request_access:dataset", kwargs={"dataset_uuid": dataset.id})) access_requests = AccessRequest.objects.all() @@ -329,8 +329,8 @@ def ticket(self): follow=True, ) - assert len(mock_zenpy_client.tickets.create.call_args_list) == 1 - call_args, _ = mock_zenpy_client.tickets.create.call_args_list[0] + assert len(mock_helpdesk_create_ticket.call_args_list) == 1 + call_args, _ = mock_helpdesk_create_ticket.call_args_list[0] ticket = call_args[0] assert ticket.subject == "Access Request for A master" diff --git a/dataworkspace/dataworkspace/tests/request_data/test_views.py b/dataworkspace/dataworkspace/tests/request_data/test_views.py index da229f846c..35eef6a287 100644 --- a/dataworkspace/dataworkspace/tests/request_data/test_views.py +++ b/dataworkspace/dataworkspace/tests/request_data/test_views.py @@ -209,7 +209,7 @@ def test_submitting_answers_fails_on_invalid_data( assert resp.status_code == expected_status_code @mock.patch("dataworkspace.apps.request_data.views.create_support_request") - def test_submitting_data_request_that_has_been_submitted_does_not_create_new_zendesk_ticket( + def test_submitting_data_request_that_has_been_submitted_does_not_create_new_help_desk_ticket( self, create_support_request_mock, client ): dr = DataRequestFactory.create(status=DataRequestStatus.submitted) @@ -241,8 +241,8 @@ def test_page_available(self, client): resp = client.get(reverse("request-data:confirmation-page", kwargs={"pk": dr.pk})) assert resp.status_code == 200 - def test_shows_zendesk_ticket_id(self, client): - dr = DataRequestFactory.create(zendesk_ticket_id="123456789-IM-A-REFERENCE-987654321") + def test_shows_help_desk_ticket_id(self, client): + dr = DataRequestFactory.create(help_desk_ticket_id="123456789-IM-A-REFERENCE-987654321") resp = client.get(reverse("request-data:confirmation-page", kwargs={"pk": dr.pk})) assert resp.status_code == 200 assert "123456789-IM-A-REFERENCE-987654321" in resp.content.decode(resp.charset) diff --git a/infra/ecs_main_admin.tf b/infra/ecs_main_admin.tf index f6bccd51d2..218397aa2b 100644 --- a/infra/ecs_main_admin.tf +++ b/infra/ecs_main_admin.tf @@ -64,11 +64,9 @@ locals { fargate_spawner__user_provided_task_role__policy_document_template_base64 = "${base64encode(data.aws_iam_policy_document.user_provided_access_template.json)}" fargate_spawner__user_provided_ecr_repository__name = "${aws_ecr_repository.user_provided.name}" - zendesk_email = "${var.zendesk_email}" - zendesk_subdomain = "${var.zendesk_subdomain}" - zendesk_token = "${var.zendesk_token}" - zendesk_service_field_id = "${var.zendesk_service_field_id}" - zendesk_service_field_value = "${var.zendesk_service_field_value}" + help_desk_email = "${var.help_desk_email}" + help_desk_service_field_id = "${var.help_desk_service_field_id}" + help_desk_service_field_value = "${var.help_desk_service_field_value}" prometheus_domain = "${var.prometheus_domain}" metrics_service_discovery_basic_auth_user = "${var.metrics_service_discovery_basic_auth_user}" diff --git a/infra/ecs_main_admin_container_definitions.json b/infra/ecs_main_admin_container_definitions.json index 725c01dee8..785b7d5c3e 100644 --- a/infra/ecs_main_admin_container_definitions.json +++ b/infra/ecs_main_admin_container_definitions.json @@ -829,24 +829,16 @@ "value": "${mirror_remote_root}" }, { - "name": "ZENDESK_EMAIL", - "value": "${zendesk_email}" + "name": "HELP_DESK_EMAIL", + "value": "${help_desk_email}" }, { - "name": "ZENDESK_SUBDOMAIN", - "value": "${zendesk_subdomain}" + "name": "HELP_DESK_SERVICE_FIELD_ID", + "value": "${help_desk_service_field_id}" }, { - "name": "ZENDESK_TOKEN", - "value": "${zendesk_token}" - }, - { - "name": "ZENDESK_SERVICE_FIELD_ID", - "value": "${zendesk_service_field_id}" - }, - { - "name": "ZENDESK_SERVICE_FIELD_VALUE", - "value": "${zendesk_service_field_value}" + "name": "HELP_DESK_SERVICE_FIELD_VALUE", + "value": "${help_desk_service_field_value}" }, { "name": "QUICKSIGHT_DASHBOARD_EMBEDDING_ROLE_ARN", diff --git a/infra/main.tf b/infra/main.tf index 16623d989e..c9135db226 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -78,11 +78,9 @@ variable healthcheck_domain {} variable prometheus_domain {} variable cloudwatch_subscription_filter {} -variable zendesk_email {} -variable zendesk_subdomain {} -variable zendesk_token {} -variable zendesk_service_field_id {} -variable zendesk_service_field_value {} +variable help_desk_email {} +variable help_desk_service_field_id {} +variable help_desk_service_field_value {} variable prometheus_whitelist { type = "list" diff --git a/requirements-dev.txt b/requirements-dev.txt index 39d87dc897..a37ab2a12a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,8 +18,6 @@ amqp==5.0.9 # kombu appdirs==1.4.4 # via pyppeteer -appnope==0.1.3 - # via ipython asgiref==3.3.4 # via # -r requirements.txt @@ -229,6 +227,8 @@ h11==0.13.0 # via wsproto hawk-server-asyncio==0.0.13 # via -r requirements.txt +helpdesk-client==0.1.7 + # via -r requirements.txt hiredis==1.1.0 # via # -r requirements.txt @@ -355,7 +355,7 @@ platformdirs==2.4.0 # pylint plotly==5.6.0 # via -r requirements.txt -pluggy==0.13.1 +pluggy==1.0.0 # via pytest prompt-toolkit==3.0.24 # via @@ -375,7 +375,7 @@ psycopg2-binary==2.9.2 # aiopg ptyprocess==0.7.0 # via pexpect -py==1.10.0 +py==1.11.0 # via pytest pycodestyle==2.7.0 # via flake8 @@ -418,7 +418,7 @@ pyrsistent==0.17.3 # jsonschema pysocks==1.7.1 # via urllib3 -pytest==6.2.4 +pytest==7.1.3 # via # -r requirements-dev.in # pytest-cov @@ -549,9 +549,10 @@ toml==0.10.2 # ipdb # pep517 # pylint +tomli==2.0.1 + # via + # black # pytest -tomli==1.2.2 - # via black tqdm==4.56.0 # via pyppeteer traitlets==5.0.5 @@ -620,8 +621,10 @@ yarl==1.5.1 # via # -r requirements.txt # aiohttp -zenpy==2.0.21 - # via -r requirements.txt +zenpy==2.0.25 + # via + # -r requirements.txt + # helpdesk-client zipp==3.8.0 # via importlib-metadata zope-event==4.5.0 diff --git a/requirements.in b/requirements.in index a18397336f..4090119718 100644 --- a/requirements.in +++ b/requirements.in @@ -49,5 +49,5 @@ sqlalchemy tableschema Werkzeug XlsxWriter -zenpy -django-webpack-loader \ No newline at end of file +django-webpack-loader +helpdesk-client diff --git a/requirements.txt b/requirements.txt index 07f024a093..f959d10afa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -143,6 +143,8 @@ greenlet==1.1.0 # via gevent hawk-server-asyncio==0.0.13 # via -r requirements.in +helpdesk-client==0.1.7 + # via -r requirements.in hiredis==1.1.0 # via aioredis idna==2.10 @@ -315,8 +317,8 @@ xlsxwriter==1.2.8 # via -r requirements.in yarl==1.5.1 # via aiohttp -zenpy==2.0.21 - # via -r requirements.in +zenpy==2.0.25 + # via helpdesk-client zope-event==4.5.0 # via gevent zope-interface==5.1.0 diff --git a/test/selenium/conftest.py b/test/selenium/conftest.py index f60d6ede38..90073f2368 100644 --- a/test/selenium/conftest.py +++ b/test/selenium/conftest.py @@ -269,11 +269,11 @@ def create_sso(is_logged_in, codes, tokens, auth_to_me): proc.join() -class ZendeskServer(multiprocessing.Process): +class HelpDeskServer(multiprocessing.Process): def run(self): submitted_tickets = [] - class ZendeskHandler(BaseHTTPRequestHandler): + class HelpDeskHandler(BaseHTTPRequestHandler): def do_GET(self): nonlocal submitted_tickets if self.path == "/_meta/read-submitted-tickets": @@ -296,17 +296,21 @@ def do_POST(self): self.send_header("Content-Type", "application/json") self.end_headers() + response_content = self.rfile.read(int(self.headers["content-length"])).decode( + "ascii" + ) + ticket_dict = json.loads(response_content) + submitted_tickets.append( - json.loads( - self.rfile.read(int(self.headers["content-length"])).decode("ascii") - ) + ticket_dict, ) - with open("test/stubs/zendesk/create-ticket.json", "rb") as stub: + with open("test/stubs/help_desk/create-ticket.json", "rb") as stub: response = BytesIO() response.write(stub.read()) self.wfile.write(response.getvalue()) + return self.send_response(500) @@ -317,7 +321,7 @@ def sys_exit(_, __): signal.signal(signal.SIGTERM, sys_exit) - httpd = HTTPServer(("0.0.0.0", 8006), ZendeskHandler) + httpd = HTTPServer(("0.0.0.0", 8006), HelpDeskHandler) try: httpd.serve_forever() finally: @@ -325,8 +329,8 @@ def sys_exit(_, __): @contextmanager -def create_zendesk(): - proc = ZendeskServer() +def create_help_desk(): + proc = HelpDeskServer() proc.start() yield proc diff --git a/test/selenium/test_request_data.py b/test/selenium/test_request_data.py index 91abd760cc..623899d06e 100644 --- a/test/selenium/test_request_data.py +++ b/test/selenium/test_request_data.py @@ -6,10 +6,11 @@ from django.core.cache import cache from dataworkspace.apps.request_data.models import RoleType, SecurityClassificationType + from test.selenium.common import get_driver # pylint: disable=wrong-import-order from test.selenium.conftest import ( # pylint: disable=wrong-import-order create_sso, - create_zendesk, + create_help_desk, ) from test.selenium.workspace_pages import ( # pylint: disable=wrong-import-order HomePage, @@ -45,7 +46,7 @@ def _application(self, create_application): } with create_sso( is_logged_in, codes, tokens, auth_to_me - ) as sso, create_zendesk() as zendesk: + ) as sso, create_help_desk() as help_desk: tries = 240 # 60 seconds while tries >= 0: try: @@ -60,14 +61,13 @@ def _application(self, create_application): self.__class__.driver = get_driver() self.__class__.sso = sso - self.__class__.zendesk = zendesk + self.__class__.help_desk = help_desk cache.clear() yield def test_happy_path(self, _application): - home_page = HomePage(self.driver) home_page.open() @@ -114,15 +114,18 @@ def test_happy_path(self, _application): # Confirm that the answers are correct confirmation_page = check_answers_page.click_accept() + assert "1234567890987654321" in confirmation_page.get_html() - # Check that the request data has been posted to Zendesk + # Check that the request data has been posted to the help desk submitted_tickets = requests.get( "http://dataworkspace.test:8006/_meta/read-submitted-tickets" ).json() assert len(submitted_tickets) == 1 + ticket_data = submitted_tickets[0]["ticket"] + assert "Bobby Tables" in ticket_data["description"] assert "It’s data about DIT" in ticket_data["description"] assert ( diff --git a/test/stubs/zendesk/create-ticket.json b/test/stubs/help_desk/create-ticket.json similarity index 100% rename from test/stubs/zendesk/create-ticket.json rename to test/stubs/help_desk/create-ticket.json