Skip to content

Commit

Permalink
Client deletion implement (#389)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Domejko authored Jun 10, 2024
1 parent cbbf492 commit 2e5dfa9
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 3 deletions.
46 changes: 46 additions & 0 deletions backend/api/clients/delete.py
Original file line number Diff line number Diff line change
@@ -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},
)
9 changes: 7 additions & 2 deletions backend/api/clients/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.urls import path
from . import fetch
from . import fetch, delete


urlpatterns = [
path(
Expand All @@ -12,6 +13,10 @@
fetch.fetch_clients_dropdown,
name="fetch dropdown",
),
path(
"delete/<int:id>/",
delete.client_delete,
name="delete",
),
]

app_name = "clients"
6 changes: 5 additions & 1 deletion frontend/templates/pages/clients/dashboard/_rows.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% load humanize %}
{% for client in clients %}
{% csrf_token %}
<tr>
<td>{{ client.id }}</td>
<td colspan="2">{{ client.name }}</td>
Expand All @@ -11,7 +12,10 @@
</button>
</div>
<div class="tooltip" data-tip="Delete">
<button class="btn btn-outline btn-error btn-sm btn-disabled">
<button class="btn btn-outline btn-error btn-sm"
hx-delete="{% url 'api:clients:delete' id=client.id %}"
hx-target="#items"
hx-confirm="Are you sure you would like to delete this client?">
<i class="fa fa-solid fa-trash"></i>
</button>
</div>
Expand Down
3 changes: 3 additions & 0 deletions frontend/templates/pages/clients/dashboard/_table.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{% if delete %}
{% component "messages_list" %}
{% endif %}
<div class="flex w-full overflow-x-auto overflow-y-hidden" id="items">
<table class="table-zebra table">
<thead>
Expand Down
36 changes: 36 additions & 0 deletions tests/api/test_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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))

0 comments on commit 2e5dfa9

Please sign in to comment.