From b3bae6f5ad2d96da8b5d36d4e407cb53322e54b2 Mon Sep 17 00:00:00 2001
From: jedi <git@m.j3d1.de>
Date: Sat, 24 Feb 2024 00:36:04 +0100
Subject: [PATCH] prevent duplicate friend requests

---
 backend/toolshed/api/friend.py        | 12 ++++++--
 backend/toolshed/tests/test_friend.py | 43 ++++++++++++++++++++++++++-
 2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/backend/toolshed/api/friend.py b/backend/toolshed/api/friend.py
index a0337c5..07ee0fc 100644
--- a/backend/toolshed/api/friend.py
+++ b/backend/toolshed/api/friend.py
@@ -64,10 +64,18 @@ class FriendsRequests(APIView, ViewSetMixin):
         befriendee_username, befriendee_domain = split_userhandle_or_throw(request.data['befriendee'])
         if befriender_domain == befriendee_domain and befriender_username == befriendee_username:
             return Response(status=status.HTTP_400_BAD_REQUEST, data={'status': 'cannot befriend yourself'})
-        if user := authenticate_request_against_local_users(request, raw_request):
+        if user := authenticate_request_against_local_users(request, raw_request):  # befriender is local
             secret = secrets.token_hex(64)
             befriendee_user = ToolshedUser.objects.filter(username=befriendee_username, domain=befriendee_domain)
-            if befriendee_user.exists():
+            if befriendee_user.exists():  # befriendee is local (both are local)
+                if user.friends.filter(username=befriendee_username, domain=befriendee_domain).exists():
+                    return Response(status=status.HTTP_208_ALREADY_REPORTED, data={'status': "exists"})
+                existing_request = FriendRequestIncoming.objects.filter(
+                    befriender_username=befriender_username,
+                    befriender_domain=befriender_domain,
+                    befriendee_user=befriendee_user.get())
+                if existing_request.exists():
+                    return Response(status=status.HTTP_208_ALREADY_REPORTED, data={'status': "exists"})
                 FriendRequestIncoming.objects.create(
                     befriender_username=befriender_username,
                     befriender_domain=befriender_domain,
diff --git a/backend/toolshed/tests/test_friend.py b/backend/toolshed/tests/test_friend.py
index d689600..31132a3 100644
--- a/backend/toolshed/tests/test_friend.py
+++ b/backend/toolshed/tests/test_friend.py
@@ -130,7 +130,7 @@ class FriendRequestListTestCase(UserTestMixin, ToolshedTestCase):
 
     def test_delete_friend_request(self):
         reply = client.delete('/api/friendrequests/{}/'.format(self.friendrequest1.id),
-                                self.f['local_user1'])
+                              self.f['local_user1'])
         self.assertEqual(reply.status_code, 204)
         self.assertEqual(FriendRequestIncoming.objects.count(), 0)
 
@@ -368,3 +368,44 @@ class FriendRequestOutgoingTestCase(UserTestMixin, ToolshedTestCase):
         self.assertEqual(befriendee.friends.count(), 1)
         self.assertEqual(befriendee.friends.first().username, befriender.username)
         self.assertEqual(befriendee.friends.first().domain, befriender.domain)
+
+
+class FriendRequestCombinedTestCase(UserTestMixin, ToolshedTestCase):
+
+    def setUp(self):
+        super().setUp()
+        self.prepare_users()
+        print(self.f)
+
+    def test_friend_request_combined(self):
+        befriender = self.f['local_user1']
+        befriendee = self.f['local_user2']
+        reply1 = client.post('/api/friendrequests/', befriender, {
+            'befriender': str(befriender),
+            'befriendee': str(befriendee),
+        })
+        secret = reply1.json()['secret']
+        reply2 = client.post('/api/friendrequests/', befriender, {
+            'befriender': str(befriender),
+            'befriender_key': befriender.public_key(),
+            'befriendee': str(befriendee),
+            'secret': secret
+        })
+
+        self.assertEqual(reply1.status_code, 201)
+        self.assertEqual(reply2.status_code, 208)
+        self.assertEqual(reply1.json()['status'], 'pending')
+        self.assertEqual(reply2.json()['status'], 'exists')
+        self.assertEqual(FriendRequestIncoming.objects.count(), 1)
+
+    def test_friend_request_already_friends(self):
+        befriender = self.f['local_user1']
+        befriendee = self.f['local_user2']
+        befriender.friends.add(befriendee.public_identity)
+        reply1 = client.post('/api/friendrequests/', befriender, {
+            'befriender': str(befriender),
+            'befriendee': str(befriendee),
+        })
+        self.assertEqual(reply1.status_code, 208)
+        self.assertEqual(reply1.json()['status'], 'exists')
+        self.assertEqual(FriendRequestIncoming.objects.count(), 0)