From a7c0994ffd511fecbc9217c47170fd88f6a0e1da Mon Sep 17 00:00:00 2001
From: a2-imeri <Alfret2.imeri@live.uwe.ac.uk>
Date: Wed, 10 Jul 2024 08:00:58 +0100
Subject: [PATCH] Add Tests for Rules

---
 MisplaceAI/process_misplaced_manager/views.py |   5 +-
 MisplaceAI/pytest.ini                         |   3 +-
 MisplaceAI/results_viewer/utils.py            |   2 +-
 .../rules/__pycache__/views.cpython-310.pyc   | Bin 5003 -> 5272 bytes
 MisplaceAI/rules/tests/test_permissions.py    | 145 +++++++++++++++
 MisplaceAI/rules/tests/test_views.py          | 172 +++++++++++++++++-
 MisplaceAI/rules/views.py                     |  18 +-
 frontend/src/services/locationApi.js          |   1 +
 8 files changed, 325 insertions(+), 21 deletions(-)
 create mode 100644 MisplaceAI/rules/tests/test_permissions.py

diff --git a/MisplaceAI/process_misplaced_manager/views.py b/MisplaceAI/process_misplaced_manager/views.py
index 0ade349..9fbceb2 100644
--- a/MisplaceAI/process_misplaced_manager/views.py
+++ b/MisplaceAI/process_misplaced_manager/views.py
@@ -41,14 +41,11 @@ class UploadedImageViewSet(viewsets.ModelViewSet):
     serializer_class = UploadedImageSerializer  # Serializer class for uploaded images
     permission_classes = [IsAuthenticated]  # Only authenticated users can access
 
-# API view for normal detection on uploaded images
+# API view for normal detection on uploaded imagesm to detect misplaced items
 @api_view(['POST'])
 @permission_classes([IsAuthenticated])
 def normal_detection(request):
     """Handle image upload, run object detection, and check for misplaced objects."""
-    print("Received request for normal detection")
-    print("Request data:", request.data)
-    print("Request FILES:", request.FILES)
     try:
         if 'capturedImageData' in request.data:
             # Process base64 encoded image data
diff --git a/MisplaceAI/pytest.ini b/MisplaceAI/pytest.ini
index 981b79b..78635f9 100644
--- a/MisplaceAI/pytest.ini
+++ b/MisplaceAI/pytest.ini
@@ -3,4 +3,5 @@ DJANGO_SETTINGS_MODULE = MisplaceAI.settings
 addopts = -v --ignore=MisplaceAI/models
 testpaths =
     rules/tests
- 
+filterwarnings =
+    ignore::django.utils.deprecation.RemovedInDjango41Warning
diff --git a/MisplaceAI/results_viewer/utils.py b/MisplaceAI/results_viewer/utils.py
index a9388e2..520b696 100644
--- a/MisplaceAI/results_viewer/utils.py
+++ b/MisplaceAI/results_viewer/utils.py
@@ -98,7 +98,7 @@ def visualize_pil_misplaced_objects(image_pil, detected_objects, misplaced_objec
     misplaced_names = [obj["class_name"] for obj in misplaced_objects]
 
     # Load a font using absolute path to the static directory
-    font_size = 40  # Set the font size (increase if needed)
+    font_size = 25  # Set the font size (increase if needed)
     font_path = os.path.join(settings.BASE_DIR, 'core/static/core/fonts/Arial.ttf')  # Path to the font file
     try:
         font = ImageFont.truetype(font_path, font_size)
diff --git a/MisplaceAI/rules/__pycache__/views.cpython-310.pyc b/MisplaceAI/rules/__pycache__/views.cpython-310.pyc
index 640e602c37df9e18fdb78e344c73f3e2edbd9abe..1b6771d072a0121af1c0f8569ec94a78e46e978f 100644
GIT binary patch
delta 2672
zcmeBHpP|W@&&$ijz`(!|Z_t;frZ$mJhVjHiZNvIpjwlXBh7^Vr)*Q}Ut|%@>h7`6G
z_8jh9o+zGN-YDK&z9>Gh7)K6&u0WJPu3(g4u27Uvu5gqvSRZGONUms<D45NaBbF;3
zCC<p;&XB^L!qdW#!jsC_%p4`*&XB^J!q>u(!UyI{x-+EkrwFt#q{s?@1*F^=QUp_k
zS{PD<z<lWx;a~<$k%=$V<(Y2rdloyEmSm*nm1HI-mZYZK;`S_dOv%m63oTA9nykp!
zAg0N9OQ;~VC^xgXI5R&lJ~=0`xHz?V@<PV<A{-1147b?xld@8iONwtXC+6f72~1wX
z6w0VD`4^KcqxfVA=Fs{gAqED9A|()^fJ!KWxWWt!3?LQ7Aj3EqSQy!uc^Hd8qRF5T
zMaIkw3=9qo3=G8)3=9mZ3{i|J3{gxej8V*~EUB#NjLnQGOexGQ49$#DY^f}%>|hZV
zofKBE5C>d{ErlH{!U-4QNZ|yFa7|`q*;y|Fauy2%1A``K5jTh}1|q~ke&xt7N=Yq>
zPpT~91BrngR3rgnv4RLmkRG-oDG*y4M96>$S&&B7%#zgH;v#vF03sB?0RRdaRgkaP
z7#J7?n0Y4KvepQJ4TZV^Y?Z|1)2sm&Sd7MI<}H?j{NfTlkfESt$-_K3m~BeEKFD&g
zncPK!AU4=@5Ys_i0}x>dBEbHFd#T76BxVBg96Q2ux7a~miqA|bLimyeB!tyL%mt;w
zCDtGZ@h~tj@G$c+aWHW(2~4(Sm7F|@-BrjEWChr5Y*4pNe#x#|kMJ)@FT$oG8<2Xm
zfCMECFOU_WfaGE3VB%q_k^-k?-^9Gc^i<E1)ZDPl)N;L))ST3kR6kAbB4v;<Dj)(B
z14U{e7AP?mfs80p3Ig%jL4+BIumuqyTZ#}igIVBsRA*pd05OU|=?9dMIheT^IXJi&
zIe54jIr#V(i$E$SFJzRQe2&?UQGD_TZt=;YoW=E^C@O-du_A4dExaHC91Y-<0FMhz
z?8%EWCqFr{Br`t`cM^+)g^U0b50d~>l{745CP#A%Ob%m}NiWg`Sqe%unw&*o2Y~Iy
zmMn}wD&fhZ$P~l{hXj}ag+dW1#1cVvg1pBAiEfa+GLt`WOH5wGC0B0_(q#ckR?zea
zQc1vKP!_|H9=Ty*fSM*bV8ZC>QV#4)P@Lw1oC!{sOwe@6B)~K|klQ@R4&+38kQ1TF
z66{295&%aII9?nf@`$wR3epA76-90!E;wMo1lU@T5!DO~44**>4HP;&Oq1VnD`u|b
z!kQ*Qs*uW2P}mlMTwVk+2Wx6{W?*0l2Kft=zd@;yjhTaqgM)*Ihpz}E2TF&WMNS~6
zbKer4%qS#0xqxSBy%hrkLr4)Q1s8#HBUce9T)?UG7F$|oPDyG}5h#yAQYk;kXW)PU
zrxb8#fMN(oDrGGy%}K?bLc16kCQsqL%MH%kE+C^VC)e;f)PwB<32F*K3R_T#32_CY
z7z0NPI1_n;%3HS7ip=7Y;v%r)!0rN-Ul7lLi#U+^x0s7lONzjr03~Qm9z^MeRMfbE
z{RS$3Zt=j<Qha7gF~kKRcNKvRV*&XNJ&}PU8x&oWCO7iGs|Ocza4ki?AW!;%2!9X(
z4sjt!`3DYmu+3oKf{SWYKNbam^q_eVVRj%$7VK592f@)2hUCLr>>&4|<dq^&f`J4v
z$h$@0;tydWw#o~X2scf35e!Yn$SPnTfYT?!jTl)a1msFYRslNzoJ+t2IP^e9oChg$
zpZrHq(bfaR1j`}_usTl$28I?aDPDm`wg@EWrzsOPIZ7yxsfc~@Q6U9OP<!JRTW)?z
zYEE$xIB3Cv4084@?&8#<%*33`s??%lNQnf>Mv$Z;Fj-DmtP+&+q9lt_i%a6uiV|~E
z%kzt}^-@xk^NSKo@{5WgnHAKE0hjvVEC+T4w#<5q!zMRBr8FnijuGU3P(i}O#>2?N
WD8R_WD8eYg2xc=2@Cz7;7y<xN!MkPv

delta 2353
zcmbQC*{#l(&&$ijz`(%pLaQUqUUed$4C9W8+J^Ov3@HpLtT`OHoKc*N3@L0W>^WSy
z+)>=QJW)KkyivShF^(L*T>dEjT!AQoT)`;8T%jl-us+Tl;arg@5k>}gh7_(8?iPj=
z?o`HR<|t8jh7_I@-WG-wUNB$GogsxUg};R%g&)ipcV|cuND&0d3xWkCQiOsTG=(Sr
zP#0pn#qU|{SXz>inpcvUoLG{YGTDx?VX`8x<m9)E*F@ME7#MD`=O<;QCYKc7VouD-
zDdL}eohg)2Zn7@3ETh<DZ|2a+2N*>Rixe0b7>eXj33(7#kb!|gfPsObn1g|VfrEjC
zk&T&$sYr0L9Iwn|H%`0BK`fi<g+K~f7#J8dIg3ESRwM!v5CvJzkzbUOS`?pDS;Pwx
zV+IjoAc7S{h=cU76-j{Dk|06~L`Z`)vSyZ~<`x&pf&>um0y_!hRuu*YhR<vuw=wZd
z-p?*Mc@Ar`5ZGX-JHXb7O%`Meu)tzGHgj*W6yz6|=zt6cd4h*&@=UfV^#&jZfX(DC
z0)+#_gAmg}QidSH2t<JW2KQEx2}sNo<Uw|X2XC>1ycM6BQiSj+3rGm7gP03Sc}grm
z4&q^8VBlezyn{Ve$QooW*g<Si2Tj)J(6vE$(iWruZhVm)h>I42&I}9;ZXk0(A;`lt
zc?O4K+Dfh>MUYY@5TOhrKw(@2Qc<J|;(~&`$Q;D72N57Mu%;Mw1_lO@eV_T@DTafI
zgM)*Ihp$L|vK+50vl;`#<Oa_EdQOlz@U&8-4dQ})S_BSCaBRZEQxkhK;mpZTPAtjH
z&%>QmLO{mqGB7YyNjs+GX6E@O<|U@5`s621*5~G$JdaB@N)Mz$9~4!bMPU2ER%44<
zV~|RC%odq}xFEkm0s@>mK_L_a5(h=xWO;6jdP@+`3S>Mq34#5M-y%@Xz>$QwVO~Z}
zMjS9<^rR#Lb`~hkGC&S-0Efh6MQ+K-{5&!ljvz57kmI1q3G6s<<bq=X904v6c|;oX
z0_j4eF>eqTEgV2bl!3%uK^DqQR^*m2NJ-5}ElKq&0;N4jkfCYvU|?YI18H&x5gwq_
z!l*XchIfCx4Fdy1ND-o>;VR+=DFLOPTWo2WIVGt@MZO>ra4G^NJrYt8Yf))VD()22
z!oV=OitjErI4gOAEU})P#P3iKwhttzDO3bbGT<x%7DW^l;P3=Fvk2s|TWqNnnZ+f=
z5XXT77gR<-JOeI9K<3|KE>0~e0(%0K;xu^>B?zM6C~^ba3CixbcwmtqpP5n&2?vn7
ziok}kfP9CZD!_>XlvaBtrwhER2bU^vEkyw!PX>aBAP@mAZiFDk4LI1rHiLZ&Dk_Um
z{a6$X(t}7nU=Je92IohxSHT_xrF6|OBp=>l2e}s|aTkSwOaxmB@@`Qmh>I{0TO|QX
z?`tM&35C{Uq;RkgK*<v+5-?JDILHb_3I{s?EwO@(I0;e)PT^8Wg-cLrPHI?YYPnuY
zYK}7g6z{{pz)&|?QCOS<#PZXWyfxWDIB)W1VcB|c?ah{(pOTtW3<+XzV1t~0i@P|r
zC^Io9vnsWy7*b||t0ZuU@-r|nL<yv1CFZ5)>lJ6@7nLNJmJ~x`4^*8OflBBiP*y7f
t*@-P9-r}&yRnJc;%}KRm1Xcc^oX^9?!w7*Qj1r7Ii~>vod;$g{1^{8@i!A^E

diff --git a/MisplaceAI/rules/tests/test_permissions.py b/MisplaceAI/rules/tests/test_permissions.py
new file mode 100644
index 0000000..8286aee
--- /dev/null
+++ b/MisplaceAI/rules/tests/test_permissions.py
@@ -0,0 +1,145 @@
+from rest_framework.test import APITestCase
+from rest_framework import status
+from django.urls import reverse
+from django.contrib.auth.models import User
+from rules.models import Item, Location
+
+class PermissionsTest(APITestCase):
+    """
+    Test suite for permissions to ensure only authenticated users can access item and location endpoints.
+    """
+
+    def setUp(self):
+        # Create a normal user and an admin user
+        self.normal_user = User.objects.create_user(username='normaluser', password='testpassword')
+        self.admin_user = User.objects.create_superuser(username='adminuser', password='adminpassword')
+        
+        # Create an item and a location
+        self.item = Item.objects.create(name='Test Item')
+        self.location = Location.objects.create(name='Test Location')
+
+    def test_normal_user_cannot_access_items(self):
+        """
+        Ensure a normal user cannot access the item management endpoints.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        
+        # Attempt to access item list
+        url = reverse('rules:admin_manage_item')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        
+        # Attempt to create an item
+        data = {'name': 'New Item'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+        # Attempt to update an item
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        data = {'name': 'Updated Item'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+        # Attempt to delete an item
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_normal_user_cannot_access_locations(self):
+        """
+        Ensure a normal user cannot access the location management endpoints.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        
+        # Attempt to access location list
+        url = reverse('rules:admin_manage_location')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        
+        # Attempt to create a location
+        data = {'name': 'New Location'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+        # Attempt to update a location
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        data = {'name': 'Updated Location'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+        # Attempt to delete a location
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_admin_user_can_access_items_and_locations(self):
+        """
+        Ensure an admin user can access the item and location management endpoints.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        
+        # Access item list
+        url = reverse('rules:admin_manage_item')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Create an item
+        data = {'name': 'New Item'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        # Update an item
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        data = {'name': 'Updated Item'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        # Delete an item
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+
+        # Access location list
+        url = reverse('rules:admin_manage_location')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Create a location
+        data = {'name': 'New Location'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        # Update a location
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        data = {'name': 'Updated Location'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        # Delete a location
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+
+    def test_normal_user_can_access_rules(self):
+        """
+        Ensure a normal user can access the rules management endpoints.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        
+        # Access rule list
+        url = reverse('rules:admin_manage_rule')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Create a rule
+        data = {'item': self.item.id, 'locations': [self.location.id]}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        # Update a rule
+        url = reverse('rules:admin_manage_rule_detail', args=[self.item.id])
+        new_item = Item.objects.create(name='New Item')
+        new_location = Location.objects.create(name='New Location')
+        data = {'item': new_item.id, 'locations': [new_location.id]}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        # Delete a rule
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
diff --git a/MisplaceAI/rules/tests/test_views.py b/MisplaceAI/rules/tests/test_views.py
index 441e11b..e501fe6 100644
--- a/MisplaceAI/rules/tests/test_views.py
+++ b/MisplaceAI/rules/tests/test_views.py
@@ -1,18 +1,49 @@
-# misplaceAI/rules/tests/test_views.py
-
 from rest_framework.test import APITestCase
 from rest_framework import status
 from django.urls import reverse
 from django.contrib.auth.models import User
-from rules.models import Item
+from rules.models import Location, Item, Rule
 
-class AdminManageItemViewTest(APITestCase):
+class UserListViewTest(APITestCase):
+    """
+    Test suite for the UserListView.
+    """
 
     def setUp(self):
         # Create a user
         self.user = User.objects.create_user(username='testuser', password='testpassword')
         self.client.force_authenticate(user=self.user)
 
+    def test_list_users(self):
+        """
+        Ensure we can list all users.
+        """
+        url = reverse('rules:user-list')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.data), 1)
+        self.assertEqual(response.data[0]['username'], 'testuser')
+
+class AdminManageItemViewTest(APITestCase):
+    """
+    Test suite for the AdminManageItemView.
+    """
+
+    def setUp(self):
+        self.user = User.objects.create_user(username='testuser', password='testpassword')
+        self.client.force_authenticate(user=self.user)
+        self.item = Item.objects.create(name='Test Item')
+
+    def test_get_items(self):
+        """
+        Ensure we can retrieve the list of items.
+        """
+        url = reverse('rules:admin_manage_item')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.data), 1)
+        self.assertEqual(response.data[0]['name'], 'Test Item')
+
     def test_create_item(self):
         """
         Ensure we can create a new item.
@@ -20,9 +51,132 @@ class AdminManageItemViewTest(APITestCase):
         url = reverse('rules:admin_manage_item')
         data = {'name': 'New Item'}
         response = self.client.post(url, data, format='json')
-        
-        # Check if the response status is 201 Created
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
-        # Check if the item was actually created
-        self.assertEqual(Item.objects.count(), 1)
-        self.assertEqual(Item.objects.get().name, 'New Item')
+        self.assertEqual(Item.objects.count(), 2)
+        self.assertEqual(Item.objects.get(id=response.data['id']).name, 'New Item')
+
+    def test_update_item(self):
+        """
+        Ensure we can update an existing item.
+        """
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        data = {'name': 'Updated Item'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(Item.objects.get(id=self.item.id).name, 'Updated Item')
+
+    def test_delete_item(self):
+        """
+        Ensure we can delete an existing item.
+        """
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+        self.assertEqual(Item.objects.count(), 0)
+
+class AdminManageLocationViewTest(APITestCase):
+    """
+    Test suite for the AdminManageLocationView.
+    """
+
+    def setUp(self):
+        self.user = User.objects.create_user(username='testuser', password='testpassword')
+        self.client.force_authenticate(user=self.user)
+        self.location = Location.objects.create(name='Test Location')
+
+    def test_get_locations(self):
+        """
+        Ensure we can retrieve the list of locations.
+        """
+        url = reverse('rules:admin_manage_location')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.data), 1)
+        self.assertEqual(response.data[0]['name'], 'Test Location')
+
+    def test_create_location(self):
+        """
+        Ensure we can create a new location.
+        """
+        url = reverse('rules:admin_manage_location')
+        data = {'name': 'New Location'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+        self.assertEqual(Location.objects.count(), 2)
+        self.assertEqual(Location.objects.get(id=response.data['id']).name, 'New Location')
+
+    def test_update_location(self):
+        """
+        Ensure we can update an existing location.
+        """
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        data = {'name': 'Updated Location'}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(Location.objects.get(id=self.location.id).name, 'Updated Location')
+
+    def test_delete_location(self):
+        """
+        Ensure we can delete an existing location.
+        """
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+        self.assertEqual(Location.objects.count(), 0)
+
+class AdminManageRuleViewTest(APITestCase):
+    """
+    Test suite for the AdminManageRuleView.
+    """
+
+    def setUp(self):
+        self.user = User.objects.create_user(username='testuser', password='testpassword')
+        self.client.force_authenticate(user=self.user)
+        self.item = Item.objects.create(name='Test Item')
+        self.location = Location.objects.create(name='Test Location')
+        self.rule = Rule.objects.create(user=self.user, item=self.item)
+        self.rule.locations.add(self.location)
+
+    def test_get_rules(self):
+        """
+        Ensure we can retrieve the list of rules.
+        """
+        url = reverse('rules:admin_manage_rule')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.data), 1)
+        self.assertEqual(response.data[0]['item']['id'], self.item.id)
+
+    def test_create_rule(self):
+        """
+        Ensure we can create a new rule.
+        """
+        url = reverse('rules:admin_manage_rule')
+        data = {'item': self.item.id, 'locations': [self.location.id]}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+        self.assertEqual(Rule.objects.count(), 2)
+        self.assertEqual(Rule.objects.get(id=response.data['id']).item.id, self.item.id)
+
+    def test_update_rule(self):
+        """
+        Ensure we can update an existing rule.
+        """
+        url = reverse('rules:admin_manage_rule_detail', args=[self.rule.id])
+        new_item = Item.objects.create(name='New Item')
+        new_location = Location.objects.create(name='New Location')
+        data = {'item': new_item.id, 'locations': [new_location.id]}
+        response = self.client.put(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        updated_rule = Rule.objects.get(id=self.rule.id)
+        self.assertEqual(updated_rule.item.id, new_item.id)
+        self.assertEqual(updated_rule.locations.first().id, new_location.id)
+
+    def test_delete_rule(self):
+        """
+        Ensure we can delete an existing rule.
+        """
+        url = reverse('rules:admin_manage_rule_detail', args=[self.rule.id])
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+        self.assertEqual(Rule.objects.count(), 0)
\ No newline at end of file
diff --git a/MisplaceAI/rules/views.py b/MisplaceAI/rules/views.py
index 615067a..94223ea 100644
--- a/MisplaceAI/rules/views.py
+++ b/MisplaceAI/rules/views.py
@@ -7,18 +7,19 @@
 from rest_framework.views import APIView
 from rest_framework.response import Response
 from rest_framework import status
-from rest_framework.permissions import IsAuthenticated
+from rest_framework.permissions import IsAuthenticated, IsAdminUser
 from django.contrib.auth.models import User
 from .models import Location, Item, Rule
 from .serializers import LocationSerializer, ItemSerializer, RuleSerializer, UserSerializer
 from django.shortcuts import get_object_or_404
+from rest_framework.decorators import permission_classes
 
+ 
 class UserListView(APIView):
     """
     View to list all users. Only accessible by authenticated users.
     """
     permission_classes = [IsAuthenticated]
-
     def get(self, request, *args, **kwargs):
         # Retrieve all user objects from the database
         users = User.objects.all()
@@ -27,12 +28,13 @@ class UserListView(APIView):
         # Return the serialized data with a 200 OK status
         return Response(serializer.data, status=status.HTTP_200_OK)
 
+
+ 
 class AdminManageItemView(APIView):
     """
     View to manage items. Only accessible by authenticated users.
     """
-    permission_classes = [IsAuthenticated]
-
+    @permission_classes([IsAuthenticated])
     def get(self, request, *args, **kwargs):
         # Retrieve all item objects from the database, ordered by name
         items = Item.objects.all().order_by('name')
@@ -40,7 +42,8 @@ class AdminManageItemView(APIView):
         serializer = ItemSerializer(items, many=True)
         # Return the serialized data with a 200 OK status
         return Response(serializer.data, status=status.HTTP_200_OK)
-
+    
+    @permission_classes([IsAdminUser])
     def post(self, request, *args, **kwargs):
         # Deserialize the incoming data into an ItemSerializer
         serializer = ItemSerializer(data=request.data)
@@ -53,6 +56,7 @@ class AdminManageItemView(APIView):
         # Return validation errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
+    @permission_classes([IsAdminUser])
     def put(self, request, item_id, *args, **kwargs):
         # Retrieve the existing item object from the database
         item = get_object_or_404(Item, id=item_id)
@@ -66,7 +70,8 @@ class AdminManageItemView(APIView):
             return Response(serializer.data, status=status.HTTP_200_OK)
         # Return validation errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
-
+   
+    @permission_classes([IsAdminUser])
     def delete(self, request, item_id, *args, **kwargs):
         # Retrieve the existing item object from the database
         item = get_object_or_404(Item, id=item_id)
@@ -123,6 +128,7 @@ class AdminManageLocationView(APIView):
         # Return a 204 No Content status to indicate successful deletion
         return Response(status=status.HTTP_204_NO_CONTENT)
 
+# misplaceAI/rules/views.py
 class AdminManageRuleView(APIView):
     """
     View to manage rules. Only accessible by authenticated users.
diff --git a/frontend/src/services/locationApi.js b/frontend/src/services/locationApi.js
index 58e95a7..e29fde8 100644
--- a/frontend/src/services/locationApi.js
+++ b/frontend/src/services/locationApi.js
@@ -1,3 +1,4 @@
+// src/services/locationApi.js
 import api, { getCsrfToken } from './api';
 
 export const addLocation = async (locationData) => {
-- 
GitLab