From 2e5dfa9cdd0d24dc4f90a4cbb5c4dcf559b3d26e Mon Sep 17 00:00:00 2001 From: Slawek Bierwiaczonek <119700507+Domejko@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:13:08 +0200 Subject: [PATCH 1/5] Client deletion implement (#389) * Added delete client function * Added delete url * Enabled delete button * Added delete to render context * Added if statment to generate toast delete msg * Updated error messages * Updated error messages * Added test case for client_delete * Code runned through linting and formatting * Added user validation --- backend/api/clients/delete.py | 46 +++++++++++++++++++ backend/api/clients/urls.py | 9 +++- .../pages/clients/dashboard/_rows.html | 6 ++- .../pages/clients/dashboard/_table.html | 3 ++ tests/api/test_clients.py | 36 +++++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 backend/api/clients/delete.py diff --git a/backend/api/clients/delete.py b/backend/api/clients/delete.py new file mode 100644 index 00000000..9159d529 --- /dev/null +++ b/backend/api/clients/delete.py @@ -0,0 +1,46 @@ +from django.contrib import messages +from django.shortcuts import render +from django.contrib.auth.decorators import login_required +from django.views.decorators.http import require_http_methods + +from backend.models import Client +from backend.types.htmx import HtmxHttpRequest + + +@require_http_methods(["DELETE"]) +@login_required +def client_delete(request: HtmxHttpRequest, id: int): + try: + client = Client.objects.get(id=id) + except Client.DoesNotExist: + messages.error(request, "Client not found") + return render(request, "pages/clients/dashboard/_table.html", {"delete": True}) + + if not client: + messages.error(request, "Client not found") + return render(request, "pages/clients/dashboard/_table.html", {"delete": True}) + + if ( + not request.user.is_authenticated + or request.user != client.user + or request.user.logged_in_as_team + and request.user.logged_in_as_team != client.organization + ): + messages.error(request, "You do not have permission to delete this client") + return render(request, "pages/clients/dashboard/_table.html", {"delete": True}) + + client.delete() + messages.success(request, f'Client "{client.name}" deleted successfully') + + if request.user.logged_in_as_team: + return render( + request, + "pages/clients/dashboard/_table.html", + {"clients": Client.objects.filter(organization=request.user.logged_in_as_team).order_by("-name"), "delete": True}, + ) + else: + return render( + request, + "pages/clients/dashboard/_table.html", + {"clients": Client.objects.filter(user=request.user).order_by("-name"), "delete": True}, + ) diff --git a/backend/api/clients/urls.py b/backend/api/clients/urls.py index 6ae98023..08f3f522 100644 --- a/backend/api/clients/urls.py +++ b/backend/api/clients/urls.py @@ -1,5 +1,6 @@ from django.urls import path -from . import fetch +from . import fetch, delete + urlpatterns = [ path( @@ -12,6 +13,10 @@ fetch.fetch_clients_dropdown, name="fetch dropdown", ), + path( + "delete//", + delete.client_delete, + name="delete", + ), ] - app_name = "clients" diff --git a/frontend/templates/pages/clients/dashboard/_rows.html b/frontend/templates/pages/clients/dashboard/_rows.html index b0f847be..cfac96bd 100644 --- a/frontend/templates/pages/clients/dashboard/_rows.html +++ b/frontend/templates/pages/clients/dashboard/_rows.html @@ -1,5 +1,6 @@ {% load humanize %} {% for client in clients %} + {% csrf_token %} {{ client.id }} {{ client.name }} @@ -11,7 +12,10 @@
-
diff --git a/frontend/templates/pages/clients/dashboard/_table.html b/frontend/templates/pages/clients/dashboard/_table.html index 61a0870c..49d2607e 100644 --- a/frontend/templates/pages/clients/dashboard/_table.html +++ b/frontend/templates/pages/clients/dashboard/_table.html @@ -1,3 +1,6 @@ +{% if delete %} + {% component "messages_list" %} +{% endif %}
diff --git a/tests/api/test_clients.py b/tests/api/test_clients.py index 67907cff..b4250bbb 100644 --- a/tests/api/test_clients.py +++ b/tests/api/test_clients.py @@ -3,6 +3,7 @@ from django.urls import reverse from model_bakery import baker +from backend.models import Client from tests.handler import ViewTestCase, assert_url_matches_view @@ -109,3 +110,38 @@ def test_search_functionality(self): self.assertIn(client1, response.context["clients"]) self.assertIn(client2, response.context["clients"]) self.assertIn(client3, response.context["clients"]) + + +class ClientAPIDelete(ViewTestCase): + def setUp(self): + super().setUp() + self.id = 1 + self.url_path = f"/api/clients/delete/{self.id}/" + self.url_name = "api:clients:delete" + self.view_function_path = "backend.api.clients.delete.client_delete" + + def test_client_delete_view_matches_with_urls_view(self): + self.assertEqual(reverse(self.url_name, args=[self.id]), self.url_path) + + def test_client_delete_view_302_for_non_authenticated_users(self): + response = self.client.delete(reverse(self.url_name, args=[self.id])) + self.assertEqual(response.status_code, 302) + + def test_client_delete_view_200_for_authenticated_users(self): + self.login_user() + client = baker.make("backend.Client", user=self.log_in_user) + response = self.client.delete(reverse(self.url_name, args=[client.id])) + self.assertEqual(response.status_code, 200) + + def test_client_delete_view_deletes_client(self): + self.login_user() + client = baker.make("backend.Client", user=self.log_in_user) + self.client.delete(reverse(self.url_name, args=[client.id])) + with self.assertRaises(Client.DoesNotExist): + Client.objects.get(id=client.id) + + def test_client_delete_view_returns_error_for_non_existent_client(self): + self.login_user() + response = self.client.delete(reverse(self.url_name, args=[999])) + self.assertEqual(response.status_code, 200) # in future should be 404 + self.assertIn("Client not found", str(response.content)) From 35e9db9fd7c10f17038289e28f64598689c8da20 Mon Sep 17 00:00:00 2001 From: Derrick Priebe Date: Mon, 10 Jun 2024 06:13:47 -0700 Subject: [PATCH 2/5] Add titles to Invoices and Clients dashboard to match Receipts dashboard layout (#408) --- frontend/templates/pages/clients/dashboard/dashboard.html | 1 + frontend/templates/pages/invoices/dashboard/dashboard.html | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/templates/pages/clients/dashboard/dashboard.html b/frontend/templates/pages/clients/dashboard/dashboard.html index 0b3b36ff..d72e774e 100644 --- a/frontend/templates/pages/clients/dashboard/dashboard.html +++ b/frontend/templates/pages/clients/dashboard/dashboard.html @@ -1,6 +1,7 @@ {% extends base|default:"base/base.html" %} {% block content %}
+
From 3c74e197fe7a7ef21e036cc64cb541a3778e311c Mon Sep 17 00:00:00 2001 From: Trey <73353716+TreyWW@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:35:42 +0100 Subject: [PATCH 4/5] enhance: Improved client creation inputs Signed-off-by: Trey <73353716+TreyWW@users.noreply.github.com> --- .../pages/clients/create/create.html | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/frontend/templates/pages/clients/create/create.html b/frontend/templates/pages/clients/create/create.html index 7b6d1e7b..c06abcef 100644 --- a/frontend/templates/pages/clients/create/create.html +++ b/frontend/templates/pages/clients/create/create.html @@ -4,7 +4,7 @@
{% csrf_token %} -
REQUIRED DETAILS
+
IDENTIFICATION DETAILS [REQUIRED]
Client ID