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

---
 MisplaceAI/MisplaceAI/test_settings.py        |   2 +
 .../__pycache__/views.cpython-310.pyc         | Bin 2744 -> 3121 bytes
 MisplaceAI/authentication/views.py            |  20 +-
 .../rules/__pycache__/views.cpython-310.pyc   | Bin 5272 -> 5607 bytes
 MisplaceAI/rules/decorators.py                |  16 ++
 MisplaceAI/rules/tests/test_items.py          | 123 ++++++++
 MisplaceAI/rules/tests/test_locations.py      | 123 ++++++++
 MisplaceAI/rules/tests/test_permissions.py    | 145 ----------
 MisplaceAI/rules/tests/test_rules.py          | 266 ++++++++++++++++++
 MisplaceAI/rules/tests/test_views.py          | 182 ------------
 MisplaceAI/rules/views.py                     | 203 +++++++------
 frontend/src/services/auth.js                 |  21 +-
 12 files changed, 684 insertions(+), 417 deletions(-)
 create mode 100644 MisplaceAI/rules/decorators.py
 create mode 100644 MisplaceAI/rules/tests/test_items.py
 create mode 100644 MisplaceAI/rules/tests/test_locations.py
 delete mode 100644 MisplaceAI/rules/tests/test_permissions.py
 create mode 100644 MisplaceAI/rules/tests/test_rules.py
 delete mode 100644 MisplaceAI/rules/tests/test_views.py

diff --git a/MisplaceAI/MisplaceAI/test_settings.py b/MisplaceAI/MisplaceAI/test_settings.py
index f1f30e9..6d795d3 100644
--- a/MisplaceAI/MisplaceAI/test_settings.py
+++ b/MisplaceAI/MisplaceAI/test_settings.py
@@ -1,3 +1,5 @@
+# MisplaceAi/MisplaceAI/test_settings.py
+
 from .settings import *
 
 # Database configuration for testing
diff --git a/MisplaceAI/authentication/__pycache__/views.cpython-310.pyc b/MisplaceAI/authentication/__pycache__/views.cpython-310.pyc
index a09863931515576a4e71ad91083391430a224427..de51a8f509729894187b8ceed750ac3d4b022d24 100644
GIT binary patch
delta 1205
zcmdlXx>15JpO=@5fq{WR&Y~~Pm472&5@Wp*0|P@ULlk2QLljdga~8`2)`bjFY^m%~
z94U+`Of3vioGHw~44N#rc!E;XGmA@7i^4Kf%afTv#y~L#0|NudSbqivhT;we28J4j
zEQT7!EXEYZUdCFMD)}0gET$Bu6y{z=Mur-e1<VT>YFSHI7O>W^E{tcaWh-GTVXt9p
zW(1L09L<a=EOVGjIJ3A?SbLem8G;#D7)rP+of#Qw*%=wC1WVXbK<e3>88aD6IJ0;l
zs@NDJ8B!Q(+3VPYp>#Q8IfEwq<Z5Qw`jt$#*o#uric*U+Zm}gMC#Mz{uVgG@VPIgm
z#hO}FlwYLDdy6kUwIsecwJ0+&C$lQGsE7|F%aK_eUzV7YnR1JzII%3Xh#f4LmR}TK
zTAW%`#0ugv7nc;>;(?eNUy`4lng=miz#}9iAl}HpFkZ+x$kj2#)#VnaYejNuK}lwQ
z-sFB3F(yrp$;(*`xP?HbFs80#C{mkj#-!+Si!He*HL)aB7!;gx3=9l>j7*F?j2w(y
zj7*Gdj2w(C|5%tg{_?RXF>*98{jU;6ju<_N-pMB!)hGXCG%+mFU|?V<QbQ%wL0ldN
z1_pkR6`<(jVBlh8VdP;d;+b5?Dl@s8>7zjrF9QQZND)ZMEe?=(^AdAYZ*deP78jT2
z7p1IZDl!5YV+<lh85kHQ?`M`aC=vm21sNC^s)RlBz(J>wT$GxUnpcvUm{Y9DUj#}h
z;J_^s2WgULaf>OE1Zk225z?Tr;D&~rLA<|r5hwswvKPsNWEDV!B8UK`+9G8TO9e!L
zf)L4*AphNBDabD_QJMUa#m-F=q(%!wXoJjWkB?8uPmYf-vH}TV3mZcQ1_qF2pV=4~
z7&sVM7<rhB3?~<|$}$>E?q|KKga{g>KrmroV9;bK0=q?cavPfh8#pjTC$C}4jshho
zu#byCIj6`JWV0EF03|6%0Dw|c5j+&YiKxf|qy!WMMV25I!mS`Lg57U7xscsa!x~i<
ztPZTij)8#z>`hyc3OlGDez5Q5069*Rqlj<vUJg^6B3Y0$$RbTvq_B1b1s5wMQLBPf
zfDHx{VADY+hfg-*)Wz)p2L=X)V31a@0~{u|b3T&?1#c0^Wkn!aq=<u<Jh_KUomEgk
HN<<O>+OPRG

delta 865
zcmdleu|t$EpO=@5fq{Wxxm-uu6yA+|NsN(l3=9mZ3{i|J3{gxej8V*~ELp4z*cLKG
zv8QrGai%Z@GiWm3;t5Jk&nzxUEegv_Ew57LQczG(05KKP@{1Hoi&Kjfiognr5=%1k
z^Yp;-leaLdv)^Kmk59=@o_v$pjB_PJkthQLLy_oYe`ZCoA|3_?27U$xhGGr|1_llW
z7Dg^+4#v%PEc}d<{h4IcZ*hRk%}dNpy~R<GSX^A5UzD<vsYn)N0?5s`SW}CN@{1<d
zvP!$IWGrG~U|`T>y2W0UnpTuroN<dSF*!N4xVTE#Gp{T$Co@GMxhORyHLoNyF{fCQ
zzX%ixMN$k547WHki{rs6CZAw+bGpTmmR}SPviTNsaY@lF9*8mVCHdK@dAGPdLP7%K
zjSLLp{k?CAfH@`x2JudgF7ZLGfuXL!AuHJ@i!d8VDS=!G@hpfX2C|5yAiuaoYH}8v
zof9uekPk$F0-#6$#4-U92rXb1NMDfz0|Nty@tF-8PCU#-5|bTRWSEM?C-bmh^^jy>
zU<fIa2I+@~PLVt)JXngr4pC-cV2A?wGchGMGw+r_W^sICX-NhsG?EibQd5c)L3$M?
zYjR{qfx@In1;l3p5vm|U4Mebm2n`Uy3L-Q?gcgVZg?y1Vh@}G}bU_5z^<V<z@*<Gm
zOeVkMaMUnGl|?8qXJBA307;sG2y>YKN;&s(fLy1^Q6x3lip$jD7N=`Pa%ur6nH7QT
z(_}5u1L@EQ5mumZW`)ERV=6SYfh6Fr@SVJxOBc5*EEyOWJV6@3uCScM{Y)Md{6!$w
W6@es?%!IgoGAoZdE4zS{h$H~b!@LOq

diff --git a/MisplaceAI/authentication/views.py b/MisplaceAI/authentication/views.py
index 554a474..f67e2f3 100644
--- a/MisplaceAI/authentication/views.py
+++ b/MisplaceAI/authentication/views.py
@@ -13,11 +13,21 @@ from .serializers import RegisterSerializer, LoginSerializer
 from django.contrib.auth.models import User
 
 class RegisterView(generics.CreateAPIView):
-    """
-    View for user registration.
-    """
-    queryset = User.objects.all()  # Queryset of all users
-    serializer_class = RegisterSerializer  # Serializer class for user registration
+    queryset = User.objects.all()
+    serializer_class = RegisterSerializer
+
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        try:
+            serializer.is_valid(raise_exception=True)
+            user = serializer.save()
+            refresh = RefreshToken.for_user(user)
+            return Response({
+                'refresh': str(refresh),
+                'access': str(refresh.access_token),
+            }, status=status.HTTP_201_CREATED)
+        except Exception as e:
+            return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
 
 class LoginView(APIView):
     """
diff --git a/MisplaceAI/rules/__pycache__/views.cpython-310.pyc b/MisplaceAI/rules/__pycache__/views.cpython-310.pyc
index 1b6771d072a0121af1c0f8569ec94a78e46e978f..42d382c54f46045ba5c3e96a83735586c16ecf95 100644
GIT binary patch
literal 5607
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
bF(|k3F!3-Vpa`P`BM+khlK_u^p@<m(KXRYA

delta 2790
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

diff --git a/MisplaceAI/rules/decorators.py b/MisplaceAI/rules/decorators.py
new file mode 100644
index 0000000..11b799a
--- /dev/null
+++ b/MisplaceAI/rules/decorators.py
@@ -0,0 +1,16 @@
+# misplaceAI/rules/decorators.py
+
+from functools import wraps
+from rest_framework.response import Response
+from rest_framework import status
+
+def admin_required(view_func):
+    """
+    Custom decorator to ensure the user is an admin.
+    """
+    @wraps(view_func)
+    def _wrapped_view(request, *args, **kwargs):
+        if not request.user.is_authenticated or not request.user.is_superuser:
+            return Response({'detail': 'Permission denied.'}, status=status.HTTP_403_FORBIDDEN)
+        return view_func(request, *args, **kwargs)
+    return _wrapped_view
diff --git a/MisplaceAI/rules/tests/test_items.py b/MisplaceAI/rules/tests/test_items.py
new file mode 100644
index 0000000..a16cab3
--- /dev/null
+++ b/MisplaceAI/rules/tests/test_items.py
@@ -0,0 +1,123 @@
+# misplaceAI/rules/tests/test_items.py
+
+"""
+Test 1: test_create_item_as_admin - Test that an admin user can create a new item.
+Test 2: test_create_item_as_normal_user - Test that a normal user cannot create a new item.
+Test 3: test_delete_item_as_admin - Test that an admin user can delete an existing item.
+Test 4: test_delete_item_as_normal_user - Test that a normal user cannot delete an existing item.
+Test 5: test_get_items_as_normal_user - Test that a normal user can retrieve the list of items.
+Test 6: test_update_item_as_admin - Test that an admin user can update an existing item.
+Test 7: test_update_item_as_normal_user - Test that a normal user cannot update an existing item.
+Test 8: test_create_item_with_invalid_data - Test that creating an item with invalid data returns validation errors.
+Test 9: test_get_item_detail_as_admin - Test that an admin user can retrieve the details of a specific item.
+Test 10: test_get_item_detail_as_normal_user - Test that a normal user can retrieve the details of a specific item.
+"""
+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
+
+class AdminManageItemViewTest(APITestCase):
+    """
+    Test suite for the AdminManageItemView.
+    """
+
+    def setUp(self):
+        self.admin_user = User.objects.create_superuser(username='adminuser', password='adminpassword')
+        self.normal_user = User.objects.create_user(username='testuser', password='testpassword')
+        self.item = Item.objects.create(name='Test Item')
+
+    def test_create_item_as_admin(self):
+        """
+        Ensure admin users can create a new item.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        url = reverse('rules:admin_manage_item')
+        data = {'name': 'New Item'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+        self.assertEqual(Item.objects.count(), 2)
+        self.assertEqual(Item.objects.get(id=response.data['id']).name, 'New Item')
+
+    def test_create_item_as_normal_user(self):
+        """
+        Ensure normal users cannot create a new item.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        url = reverse('rules:admin_manage_item')
+        data = {'name': 'New Item'}
+        response = self.client.post(url, data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_delete_item_as_admin(self):
+        """
+        Ensure admin users can delete an existing item.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        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)
+
+    def test_delete_item_as_normal_user(self):
+        """
+        Ensure normal users cannot delete an existing item.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_get_items_as_normal_user(self):
+        """
+        Ensure normal users can retrieve the list of items.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        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_update_item_as_admin(self):
+        """
+        Ensure admin users can update an existing item.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        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_update_item_as_normal_user(self):
+        """
+        Ensure normal users cannot update an existing item.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        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)
+    
+    def test_create_item_with_invalid_data(self):
+        self.client.force_authenticate(user=self.admin_user)
+        url = reverse('rules:admin_manage_item')
+        data = {'invalid_field': 'invalid_data'}
+        response = self.client.post(url, data, format='json')
+        assert response.status_code == status.HTTP_400_BAD_REQUEST
+
+    def test_get_item_detail_as_admin(self):
+        self.client.force_authenticate(user=self.admin_user)
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        response = self.client.get(url)
+        assert response.status_code == status.HTTP_200_OK
+
+    def test_get_item_detail_as_normal_user(self):
+        self.client.force_authenticate(user=self.normal_user)
+        url = reverse('rules:admin_manage_item_detail', args=[self.item.id])
+        response = self.client.get(url)
+        assert response.status_code == status.HTTP_200_OK
+
+            
diff --git a/MisplaceAI/rules/tests/test_locations.py b/MisplaceAI/rules/tests/test_locations.py
new file mode 100644
index 0000000..5c1ee11
--- /dev/null
+++ b/MisplaceAI/rules/tests/test_locations.py
@@ -0,0 +1,123 @@
+# misplaceAI/rules/tests/test_locations.py
+
+
+"""
+Test 1: test_create_location_as_admin - Test that an admin user can create a new location.
+Test 2: test_create_location_as_normal_user - Test that a normal user cannot create a new location.
+Test 3: test_delete_location_as_admin - Test that an admin user can delete an existing location.
+Test 4: test_delete_location_as_normal_user - Test that a normal user cannot delete an existing location.
+Test 5: test_get_locations_as_normal_user - Test that a normal user can retrieve the list of locations.
+Test 6: test_update_location_as_admin - Test that an admin user can update an existing location.
+Test 7: test_update_location_as_normal_user - Test that a normal user cannot update an existing location.
+Test 8: test_create_location_with_invalid_data - Test that creating a location with invalid data returns validation errors.
+Test 9: test_get_location_detail_as_admin - Test that an admin user can retrieve the details of a specific location.
+Test 10: test_get_location_detail_as_normal_user - Test that a normal user can retrieve the details of a specific location.
+"""
+
+
+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 Location
+
+class AdminManageLocationViewTest(APITestCase):
+    """
+    Test suite for the AdminManageLocationView.
+    """
+
+    def setUp(self):
+        self.admin_user = User.objects.create_superuser(username='adminuser', password='adminpassword')
+        self.normal_user = User.objects.create_user(username='testuser', password='testpassword')
+        self.location = Location.objects.create(name='Test Location')
+
+    def test_create_location_as_admin(self):
+        """
+        Ensure admin users can create a new location.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        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_create_location_as_normal_user(self):
+        """
+        Ensure normal users cannot create a new location.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        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_403_FORBIDDEN)
+
+    def test_delete_location_as_admin(self):
+        """
+        Ensure admin users can delete an existing location.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        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)
+
+    def test_delete_location_as_normal_user(self):
+        """
+        Ensure normal users cannot delete an existing location.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        response = self.client.delete(url)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_get_locations_as_normal_user(self):
+        """
+        Ensure normal users can retrieve the list of locations.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        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_update_location_as_admin(self):
+        """
+        Ensure admin users can update an existing location.
+        """
+        self.client.force_authenticate(user=self.admin_user)
+        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_update_location_as_normal_user(self):
+        """
+        Ensure normal users cannot update an existing location.
+        """
+        self.client.force_authenticate(user=self.normal_user)
+        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)
+    def test_create_location_with_invalid_data(self):
+        self.client.force_authenticate(user=self.admin_user)
+        url = reverse('rules:admin_manage_location')
+        data = {'invalid_field': 'invalid_data'}
+        response = self.client.post(url, data, format='json')
+        assert response.status_code == status.HTTP_400_BAD_REQUEST
+
+    def test_get_location_detail_as_admin(self):
+        self.client.force_authenticate(user=self.admin_user)
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        response = self.client.get(url)
+        assert response.status_code == status.HTTP_200_OK
+
+    def test_get_location_detail_as_normal_user(self):
+        self.client.force_authenticate(user=self.normal_user)
+        url = reverse('rules:admin_manage_location_detail', args=[self.location.id])
+        response = self.client.get(url)
+        assert response.status_code == status.HTTP_200_OK
diff --git a/MisplaceAI/rules/tests/test_permissions.py b/MisplaceAI/rules/tests/test_permissions.py
deleted file mode 100644
index 8286aee..0000000
--- a/MisplaceAI/rules/tests/test_permissions.py
+++ /dev/null
@@ -1,145 +0,0 @@
-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_rules.py b/MisplaceAI/rules/tests/test_rules.py
new file mode 100644
index 0000000..33cdab6
--- /dev/null
+++ b/MisplaceAI/rules/tests/test_rules.py
@@ -0,0 +1,266 @@
+# misplaceAI/rules/tests/test_rules.py
+
+"""
+Test 1: test_create_rule - Test that a rule can be created with valid data by the owner.
+Test 2: test_create_rule_with_invalid_data - Test that creating a rule with invalid data fails.
+Test 3: test_create_rule_without_association - Test that creating a rule without locations fails.
+Test 4: test_delete_rule_as_non_owner - Test that a non-owner cannot delete a rule.
+Test 5: test_delete_rule_as_owner - Test that the owner can delete their rule.
+Test 6: test_get_rule_detail_as_non_owner - Test that a non-owner cannot access the details of a rule.
+Test 7: test_get_rule_detail_as_owner - Test that the owner can access the details of their rule.
+Test 8: test_get_rules_as_non_owner - Test that a non-owner cannot access the list of rules of the owner.
+Test 9: test_get_rules_as_owner - Test that the owner can access the list of their rules.
+Test 10: test_rule_association_with_multiple_locations - Test that a rule can be associated with multiple locations.
+Test 11: test_update_rule_as_non_owner - Test that a non-owner cannot update a rule.
+Test 12: test_update_rule_as_owner - Test that the owner can update their rule.
+"""
+
+from rest_framework import status
+from rest_framework.reverse import reverse
+from rest_framework.test import APITestCase
+from django.contrib.auth.models import User
+from rules.models import Item, Location, Rule
+
+class TestAdminManageRuleView(APITestCase):
+    def setUp(self):
+        """
+        Set up test data for the test cases.
+        """
+        # Create users
+        self.owner = User.objects.create_user(username='owner', password='password')
+        self.non_owner = User.objects.create_user(username='non_owner', password='password')
+        
+        # Create an item
+        self.item = Item.objects.create(name='Test Item')
+        
+        # Create a location
+        self.location = Location.objects.create(name='Test Location')
+        
+        # Create a rule associated with the owner
+        self.rule = Rule.objects.create(user=self.owner, item=self.item)
+        self.rule.locations.set([self.location])
+        
+        # Define URLs for rule management
+        self.url = reverse('rules:admin_manage_rule')
+        self.detail_url = lambda rule_id: reverse('rules:admin_manage_rule_detail', args=[rule_id])
+
+    def test_create_rule(self):
+        """
+        Test 1: test_create_rule - Test that a rule can be created with valid data by the owner.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Define the data for the new rule
+        data = {
+            'item': self.item.id,
+            'locations': [self.location.id]
+        }
+        
+        # Send a POST request to create the rule
+        response = self.client.post(self.url, data, format='json')
+        
+        # Assert that the rule is created successfully
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+    def test_create_rule_with_invalid_data(self):
+        """
+        Test 2: test_create_rule_with_invalid_data - Test that creating a rule with invalid data fails.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Define invalid data for the new rule
+        data = {
+            'item': '',
+            'locations': []
+        }
+        
+        # Send a POST request with invalid data
+        response = self.client.post(self.url, data, format='json')
+        
+        # Assert that the request fails with a 400 Bad Request status
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+    def test_create_rule_without_association(self):
+        """
+        Test 3: test_create_rule_without_association - Test that creating a rule without locations fails.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Define data for the new rule without locations
+        data = {
+            'item': self.item.id,
+            'locations': []
+        }
+        
+        # Send a POST request with incomplete data
+        response = self.client.post(self.url, data, format='json')
+        
+        # Assert that the request fails with a 400 Bad Request status
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+    def test_delete_rule_as_non_owner(self):
+        """
+        Test 4: test_delete_rule_as_non_owner - Test that a non-owner cannot delete a rule.
+        """
+        # Authenticate as the non-owner
+        self.client.force_authenticate(user=self.non_owner)
+        
+        # Send a DELETE request for the rule
+        response = self.client.delete(self.detail_url(self.rule.id))
+        
+        # Assert that the request fails with a 403 Forbidden status
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_delete_rule_as_owner(self):
+        """
+        Test 5: test_delete_rule_as_owner - Test that the owner can delete their rule.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Send a DELETE request for the rule
+        response = self.client.delete(self.detail_url(self.rule.id))
+        
+        # Assert that the rule is deleted successfully with a 204 No Content status
+        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+
+    def test_get_rule_detail_as_non_owner(self):
+        """
+        Test 6: test_get_rule_detail_as_non_owner - Test that a non-owner cannot access the details of a rule.
+        """
+        # Authenticate as the non-owner
+        self.client.force_authenticate(user=self.non_owner)
+        
+        # Send a GET request for the rule detail
+        response = self.client.get(self.detail_url(self.rule.id))
+        
+        # Assert that the request fails with a 403 Forbidden status
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_get_rule_detail_as_owner(self):
+        """
+        Test 7: test_get_rule_detail_as_owner - Test that the owner can access the details of their rule.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Send a GET request for the rule detail
+        response = self.client.get(self.detail_url(self.rule.id))
+        
+        # Assert that the request is successful with a 200 OK status
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Assert that the returned rule ID matches the rule's ID
+        self.assertEqual(response.data['id'], self.rule.id)
+
+    def test_get_rules_as_non_owner(self):
+        """
+        Test 8: test_get_rules_as_non_owner - Test that a non-owner cannot access the list of rules of the owner.
+        """
+        # Authenticate as the non-owner
+        self.client.force_authenticate(user=self.non_owner)
+        
+        # Send a GET request for the list of rules
+        response = self.client.get(self.url)
+        
+        # Assert that the request is successful with a 200 OK status
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Assert that the non-owner sees an empty list
+        self.assertEqual(response.data, [])
+
+    def test_get_rules_as_owner(self):
+        """
+        Test 9: test_get_rules_as_owner - Test that the owner can access the list of their rules.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Send a GET request for the list of rules
+        response = self.client.get(self.url)
+        
+        # Assert that the request is successful with a 200 OK status
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Assert that the returned list contains one rule
+        self.assertEqual(len(response.data), 1)
+        
+        # Assert that the returned rule ID matches the rule's ID
+        self.assertEqual(response.data[0]['id'], self.rule.id)
+
+    def test_rule_association_with_multiple_locations(self):
+        """
+        Test 10: test_rule_association_with_multiple_locations - Test that a rule can be associated with multiple locations.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Create a new location
+        new_location = Location.objects.create(name='New Location')
+        
+        # Define the data for updating the rule with multiple locations
+        data = {
+            'item': self.item.id,
+            'locations': [self.location.id, new_location.id]
+        }
+        
+        # Send a PUT request to update the rule
+        response = self.client.put(self.detail_url(self.rule.id), data, format='json')
+        
+        # Assert that the request is successful with a 200 OK status
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Assert that the rule is associated with two locations
+        self.assertEqual(len(response.data['locations']), 2)
+
+    def test_update_rule_as_non_owner(self):
+        """
+        Test 11: test_update_rule_as_non_owner - Test that a non-owner cannot update a rule.
+        """
+        # Authenticate as the non-owner
+        self.client.force_authenticate(user=self.non_owner)
+        
+        # Create a new item and location
+        new_item = Item.objects.create(name='New Item')
+        new_location = Location.objects.create(name='New Location')
+        
+        # Define the data for updating the rule
+        data = {
+            'item': new_item.id,
+            'locations': [new_location.id]
+        }
+        
+        # Send a PUT request to update the rule
+        response = self.client.put(self.detail_url(self.rule.id), data, format='json')
+        
+        # Assert that the request fails with a 403 Forbidden status
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_update_rule_as_owner(self):
+        """
+        Test 12: test_update_rule_as_owner - Test that the owner can update their rule.
+        """
+        # Authenticate as the owner
+        self.client.force_authenticate(user=self.owner)
+        
+        # Create a new item and location
+        new_item = Item.objects.create(name='New Item')
+        new_location = Location.objects.create(name='New Location')
+        
+        # Define the data for updating the rule
+        data = {
+            'item': new_item.id,
+            'locations': [new_location.id]
+        }
+        
+        # Send a PUT request to update the rule
+        response = self.client.put(self.detail_url(self.rule.id), data, format='json')
+        
+        # Assert that the request is successful with a 200 OK status
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        
+        # Assert that the returned rule ID matches the rule's ID
+        self.assertEqual(response.data['id'], self.rule.id)
diff --git a/MisplaceAI/rules/tests/test_views.py b/MisplaceAI/rules/tests/test_views.py
deleted file mode 100644
index e501fe6..0000000
--- a/MisplaceAI/rules/tests/test_views.py
+++ /dev/null
@@ -1,182 +0,0 @@
-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 Location, Item, Rule
-
-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.
-        """
-        url = reverse('rules:admin_manage_item')
-        data = {'name': 'New Item'}
-        response = self.client.post(url, data, format='json')
-        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
-        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 94223ea..c7857ab 100644
--- a/MisplaceAI/rules/views.py
+++ b/MisplaceAI/rules/views.py
@@ -1,213 +1,252 @@
 # misplaceAI/rules/views.py
 
-# This file defines the views for the rules app.
-# Views handle the logic for different endpoints, providing appropriate responses
-# based on the request and the business logic. This includes managing users, items, locations, and rules.
-
+from django.utils.decorators import method_decorator
 from rest_framework.views import APIView
 from rest_framework.response import Response
 from rest_framework import status
-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 rest_framework.permissions import IsAuthenticated
 from django.shortcuts import get_object_or_404
-from rest_framework.decorators import permission_classes
+from django.contrib.auth.models import User
+from .models import Item, Location, Rule
+from .serializers import ItemSerializer, LocationSerializer, UserSerializer, RuleSerializer
+from .decorators import admin_required
 
- 
 class UserListView(APIView):
-    """
-    View to list all users. Only accessible by authenticated users.
-    """
+    # Only authenticated users can access this view
     permission_classes = [IsAuthenticated]
+
     def get(self, request, *args, **kwargs):
-        # Retrieve all user objects from the database
+        # Retrieve all users from the database
         users = User.objects.all()
-        # Serialize the user objects into JSON format
+        # Serialize the user objects
         serializer = UserSerializer(users, many=True)
         # 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])
+    # Only authenticated users can access this view
+    permission_classes = [IsAuthenticated]
+
     def get(self, request, *args, **kwargs):
-        # Retrieve all item objects from the database, ordered by name
+        # Retrieve all items from the database, ordered by name
         items = Item.objects.all().order_by('name')
-        # Serialize the item objects into JSON format
+        # Serialize the item objects
         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])
+
+    @method_decorator(admin_required)
     def post(self, request, *args, **kwargs):
-        # Deserialize the incoming data into an ItemSerializer
+        # Deserialize the request data into an ItemSerializer
         serializer = ItemSerializer(data=request.data)
-        # Validate the data
+        # Check if the data is valid
         if serializer.is_valid():
-            # Save the new item object to the database
+            # Save the new item to the database
             serializer.save()
             # Return the serialized data with a 201 Created status
             return Response(serializer.data, status=status.HTTP_201_CREATED)
-        # Return validation errors with a 400 Bad Request status
+        # Return the errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
-    @permission_classes([IsAdminUser])
+    @method_decorator(admin_required)
     def put(self, request, item_id, *args, **kwargs):
-        # Retrieve the existing item object from the database
+        # Retrieve the existing item or return 404 if not found
         item = get_object_or_404(Item, id=item_id)
-        # Deserialize the incoming data into an ItemSerializer
+        # Deserialize the request data into an ItemSerializer
         serializer = ItemSerializer(item, data=request.data)
-        # Validate the data
+        # Check if the data is valid
         if serializer.is_valid():
-            # Update the existing item object in the database
+            # Save the updated item to the database
             serializer.save()
             # Return the serialized data with a 200 OK status
             return Response(serializer.data, status=status.HTTP_200_OK)
-        # Return validation errors with a 400 Bad Request status
+        # Return the errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
-   
-    @permission_classes([IsAdminUser])
+
+    @method_decorator(admin_required)
     def delete(self, request, item_id, *args, **kwargs):
-        # Retrieve the existing item object from the database
+        # Retrieve the existing item or return 404 if not found
         item = get_object_or_404(Item, id=item_id)
-        # Delete the item object from the database
+        # Delete the item from the database
         item.delete()
         # Return a 204 No Content status to indicate successful deletion
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 class AdminManageLocationView(APIView):
-    """
-    View to manage locations. Only accessible by authenticated users.
-    """
+    # Only authenticated users can access this view
     permission_classes = [IsAuthenticated]
 
     def get(self, request, *args, **kwargs):
-        # Retrieve all location objects from the database, ordered by name
+        # Retrieve all locations from the database, ordered by name
         locations = Location.objects.all().order_by('name')
-        # Serialize the location objects into JSON format
+        # Serialize the location objects
         serializer = LocationSerializer(locations, many=True)
         # Return the serialized data with a 200 OK status
         return Response(serializer.data, status=status.HTTP_200_OK)
 
+    @method_decorator(admin_required)
     def post(self, request, *args, **kwargs):
-        # Deserialize the incoming data into a LocationSerializer
+        # Deserialize the request data into a LocationSerializer
         serializer = LocationSerializer(data=request.data)
-        # Validate the data
+        # Check if the data is valid
         if serializer.is_valid():
-            # Save the new location object to the database
+            # Save the new location to the database
             serializer.save()
             # Return the serialized data with a 201 Created status
             return Response(serializer.data, status=status.HTTP_201_CREATED)
-        # Return validation errors with a 400 Bad Request status
+        # Return the errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
+    @method_decorator(admin_required)
     def put(self, request, location_id, *args, **kwargs):
-        # Retrieve the existing location object from the database
+        # Retrieve the existing location or return 404 if not found
         location = get_object_or_404(Location, id=location_id)
-        # Deserialize the incoming data into a LocationSerializer
+        # Deserialize the request data into a LocationSerializer
         serializer = LocationSerializer(location, data=request.data)
-        # Validate the data
+        # Check if the data is valid
         if serializer.is_valid():
-            # Update the existing location object in the database
+            # Save the updated location to the database
             serializer.save()
             # Return the serialized data with a 200 OK status
             return Response(serializer.data, status=status.HTTP_200_OK)
-        # Return validation errors with a 400 Bad Request status
+        # Return the errors with a 400 Bad Request status
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
+    @method_decorator(admin_required)
     def delete(self, request, location_id, *args, **kwargs):
-        # Retrieve the existing location object from the database
+        # Retrieve the existing location or return 404 if not found
         location = get_object_or_404(Location, id=location_id)
-        # Delete the location object from the database
+        # Delete the location from the database
         location.delete()
         # 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.
     """
-    permission_classes = [IsAuthenticated]
-
-    def get(self, request, *args, **kwargs):
-        # Filter rules based on the authenticated user
-        rules = Rule.objects.filter(user=request.user).order_by('id')
-        # Serialize the rule objects into JSON format
-        serializer = RuleSerializer(rules, many=True)
-        # Return the serialized data with a 200 OK status
+    permission_classes = [IsAuthenticated]  # Only authenticated users can access this view
+
+    def get(self, request, rule_id=None, *args, **kwargs):
+        """
+        Retrieve a list of rules for the authenticated user or a specific rule.
+        """
+        # Check if a specific rule ID is provided
+        if rule_id:
+            # Retrieve the rule or return 404 if not found
+            rule = get_object_or_404(Rule, id=rule_id)
+            # Ensure the rule belongs to the authenticated user
+            if rule.user != request.user:
+                # Return 403 Forbidden if the user does not own the rule
+                return Response(status=status.HTTP_403_FORBIDDEN)
+            # Serialize the rule object
+            serializer = RuleSerializer(rule)
+        else:
+            # Retrieve all rules for the authenticated user
+            rules = Rule.objects.filter(user=request.user).order_by('id')
+            # Serialize the list of rule objects
+            serializer = RuleSerializer(rules, many=True)
+        # Return the serialized data with 200 OK status
         return Response(serializer.data, status=status.HTTP_200_OK)
 
     def post(self, request, *args, **kwargs):
-        # Extract the item ID and location IDs from the request data
+        """
+        Create a new rule associated with the authenticated user.
+        """
+        # Get the data from the request
         data = request.data
+        # Get the item ID from the data
         item_id = data.get('item')
+        # Get the list of location IDs from the data
         location_ids = data.get('locations', [])
 
+        # Check if both item ID and location IDs are provided
+        if not item_id or not location_ids:
+            # Return 400 Bad Request if not
+            return Response({'error': 'Item and locations are required.'}, status=status.HTTP_400_BAD_REQUEST)
+
         # Get the authenticated user
         user = request.user
-        # Retrieve the item object from the database
+        # Retrieve the item object or return 404 if not found
         item = get_object_or_404(Item, id=item_id)
-        # Retrieve the location objects from the database
+        # Retrieve the location objects for the provided IDs
         locations = Location.objects.filter(id__in=location_ids)
 
         # Check if the locations exist
         if not locations.exists():
-            # Return an error if one or more locations are invalid
+            # Return 400 Bad Request if not
             return Response({'error': 'One or more locations are invalid.'}, status=status.HTTP_400_BAD_REQUEST)
 
         # Create a new rule object
         rule = Rule(user=user, item=item)
         # Save the rule object to the database
         rule.save()
-        # Set the locations for the rule
+        # Associate the locations with the rule
         rule.locations.set(locations)
-        # Save the rule object to the database
+        # Save the rule object again to update the associations
         rule.save()
 
-        # Serialize the rule object into JSON format
+        # Serialize the rule object
         serializer = RuleSerializer(rule)
-        # Return the serialized data with a 201 Created status
+        # Return the serialized data with 201 Created status
         return Response(serializer.data, status=status.HTTP_201_CREATED)
 
     def put(self, request, rule_id, *args, **kwargs):
-        # Retrieve the existing rule object from the database
+        """
+        Update an existing rule for the authenticated user.
+        """
+        # Retrieve the existing rule object from the database and ensure it belongs to the user
         rule = get_object_or_404(Rule, id=rule_id)
-        # Extract the item ID and location IDs from the request data
+        # Ensure the rule belongs to the authenticated user
+        if rule.user != request.user:
+            # Return 403 Forbidden if the user does not own the rule
+            return Response(status=status.HTTP_403_FORBIDDEN)
+            
+        # Get the data from the request
         data = request.data
+        # Get the item ID from the data
         item_id = data.get('item')
+        # Get the list of location IDs from the data
         location_ids = data.get('locations', [])
 
-        # Retrieve the item object from the database
+        # Retrieve the item object or return 404 if not found
         item = get_object_or_404(Item, id=item_id)
-        # Retrieve the location objects from the database
+        # Retrieve the location objects for the provided IDs
         locations = Location.objects.filter(id__in=location_ids)
 
         # Check if the locations exist
         if not locations.exists():
-            # Return an error if one or more locations are invalid
+            # Return 400 Bad Request if not
             return Response({'error': 'One or more locations are invalid.'}, status=status.HTTP_400_BAD_REQUEST)
 
-        # Update the rule object with the new item and locations
+        # Update the item associated with the rule
         rule.item = item
+        # Update the locations associated with the rule
         rule.locations.set(locations)
         # Save the updated rule object to the database
         rule.save()
 
-        # Serialize the rule object into JSON format
+        # Serialize the rule object
         serializer = RuleSerializer(rule)
-        # Return the serialized data with a 200 OK status
+        # Return the serialized data with 200 OK status
         return Response(serializer.data, status=status.HTTP_200_OK)
 
     def delete(self, request, rule_id, *args, **kwargs):
-        # Retrieve the existing rule object from the database
+        """
+        Delete an existing rule for the authenticated user.
+        """
+        # Retrieve the rule object or return 404 if not found
         rule = get_object_or_404(Rule, id=rule_id)
+        # Ensure the rule belongs to the authenticated user
+        if rule.user != request.user:
+            # Return 403 Forbidden if the user does not own the rule
+            return Response(status=status.HTTP_403_FORBIDDEN)
         # Delete the rule object from the database
         rule.delete()
-        # Return a 204 No Content status to indicate successful deletion
+        # Return 204 No Content status to indicate successful deletion
         return Response(status=status.HTTP_204_NO_CONTENT)
diff --git a/frontend/src/services/auth.js b/frontend/src/services/auth.js
index b9ea689..866bbdc 100644
--- a/frontend/src/services/auth.js
+++ b/frontend/src/services/auth.js
@@ -13,11 +13,26 @@ export const login = async (credentials) => {
 
 // Register function for new users
 export const register = async (userData) => {
-    const data = await obtainToken('/api/auth/register/', userData);
-    localStorage.setItem('isAuthenticated', true);
-    return data;
+    try {
+        const data = await obtainToken('/api/auth/register/', userData);
+        localStorage.setItem('isAuthenticated', true);
+        return data;
+    } catch (error) {
+        if (error.response) {
+            // The request was made and the server responded with a status code outside of the range of 2xx
+            console.error('Registration failed:', error.response.data);
+        } else if (error.request) {
+            // The request was made but no response was received
+            console.error('No response received:', error.request);
+        } else {
+            // Something happened in setting up the request that triggered an error
+            console.error('Error in registration request setup:', error.message);
+        }
+        throw error;
+    }
 };
 
+
 // Admin login function
 export const adminLogin = async (credentials) => {
     const data = await obtainToken('/api/auth/admin/login/', credentials);
-- 
GitLab