prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  It's possible to create a FollowRequest for a Follow that already exists
  Send a follow request.
  User accepts.
  Send a second follow request (eg. using an old tab)
  
  Because requests and follows are stored in separate tables it's not possible to enforce this with a constraint. Pre-checking would leave a race condition, so I guess we either need to mess with table locks or create the follow request, and then delete it if its unneeded. Can we enforce this in the pre save of the model, perhaps?
  
  </issue>
  <code>
  [start of bookwyrm/models/relationship.py]
  1 ''' defines relationships between users '''
  2 from django.db import models
  3 
  4 from bookwyrm import activitypub
  5 from .base_model import ActivitypubMixin, ActivityMapping, BookWyrmModel
  6 
  7 
  8 class UserRelationship(ActivitypubMixin, BookWyrmModel):
  9     ''' many-to-many through table for followers '''
  10     user_subject = models.ForeignKey(
  11         'User',
  12         on_delete=models.PROTECT,
  13         related_name='%(class)s_user_subject'
  14     )
  15     user_object = models.ForeignKey(
  16         'User',
  17         on_delete=models.PROTECT,
  18         related_name='%(class)s_user_object'
  19     )
  20 
  21     class Meta:
  22         ''' relationships should be unique '''
  23         abstract = True
  24         constraints = [
  25             models.UniqueConstraint(
  26                 fields=['user_subject', 'user_object'],
  27                 name='%(class)s_unique'
  28             ),
  29             models.CheckConstraint(
  30                 check=~models.Q(user_subject=models.F('user_object')),
  31                 name='%(class)s_no_self'
  32             )
  33         ]
  34 
  35     activity_mappings = [
  36         ActivityMapping('id', 'remote_id'),
  37         ActivityMapping('actor', 'user_subject'),
  38         ActivityMapping('object', 'user_object'),
  39     ]
  40     activity_serializer = activitypub.Follow
  41 
  42     def get_remote_id(self, status=None):
  43         ''' use shelf identifier in remote_id '''
  44         status = status or 'follows'
  45         base_path = self.user_subject.remote_id
  46         return '%s#%s/%d' % (base_path, status, self.id)
  47 
  48 
  49     def to_accept_activity(self):
  50         ''' generate an Accept for this follow request '''
  51         return activitypub.Accept(
  52             id=self.get_remote_id(status='accepts'),
  53             actor=self.user_object.remote_id,
  54             object=self.to_activity()
  55         ).serialize()
  56 
  57 
  58     def to_reject_activity(self):
  59         ''' generate an Accept for this follow request '''
  60         return activitypub.Reject(
  61             id=self.get_remote_id(status='rejects'),
  62             actor=self.user_object.remote_id,
  63             object=self.to_activity()
  64         ).serialize()
  65 
  66 
  67 class UserFollows(UserRelationship):
  68     ''' Following a user '''
  69     status = 'follows'
  70 
  71     @classmethod
  72     def from_request(cls, follow_request):
  73         ''' converts a follow request into a follow relationship '''
  74         return cls(
  75             user_subject=follow_request.user_subject,
  76             user_object=follow_request.user_object,
  77             remote_id=follow_request.remote_id,
  78         )
  79 
  80 
  81 class UserFollowRequest(UserRelationship):
  82     ''' following a user requires manual or automatic confirmation '''
  83     status = 'follow_request'
  84 
  85 
  86 class UserBlocks(UserRelationship):
  87     ''' prevent another user from following you and seeing your posts '''
  88     # TODO: not implemented
  89     status = 'blocks'
  90
  [end of bookwyrm/models/relationship.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/bookwyrm/models/relationship.py b/bookwyrm/models/relationship.py
  --- a/bookwyrm/models/relationship.py
  +++ b/bookwyrm/models/relationship.py
  @@ -82,6 +82,17 @@
       ''' following a user requires manual or automatic confirmation '''
       status = 'follow_request'
   
  +    def save(self, *args, **kwargs):
  +        ''' make sure the follow relationship doesn't already exist '''
  +        try:
  +            UserFollows.objects.get(
  +                user_subject=self.user_subject,
  +                user_object=self.user_object
  +            )
  +            return None
  +        except UserFollows.DoesNotExist:
  +            return super().save(*args, **kwargs)
  +
   
   class UserBlocks(UserRelationship):
       ''' prevent another user from following you and seeing your posts '''
  
verification_info: {"golden_diff": "diff --git a/bookwyrm/models/relationship.py b/bookwyrm/models/relationship.py\n--- a/bookwyrm/models/relationship.py\n+++ b/bookwyrm/models/relationship.py\n@@ -82,6 +82,17 @@\n     ''' following a user requires manual or automatic confirmation '''\n     status = 'follow_request'\n \n+    def save(self, *args, **kwargs):\n+        ''' make sure the follow relationship doesn't already exist '''\n+        try:\n+            UserFollows.objects.get(\n+                user_subject=self.user_subject,\n+                user_object=self.user_object\n+            )\n+            return None\n+        except UserFollows.DoesNotExist:\n+            return super().save(*args, **kwargs)\n+\n \n class UserBlocks(UserRelationship):\n     ''' prevent another user from following you and seeing your posts '''\n", "issue": "It's possible to create a FollowRequest for a Follow that already exists\nSend a follow request.\r\nUser accepts.\r\nSend a second follow request (eg. using an old tab)\r\n\r\nBecause requests and follows are stored in separate tables it's not possible to enforce this with a constraint. Pre-checking would leave a race condition, so I guess we either need to mess with table locks or create the follow request, and then delete it if its unneeded. Can we enforce this in the pre save of the model, perhaps?\n", "before_files": [{"content": "''' defines relationships between users '''\nfrom django.db import models\n\nfrom bookwyrm import activitypub\nfrom .base_model import ActivitypubMixin, ActivityMapping, BookWyrmModel\n\n\nclass UserRelationship(ActivitypubMixin, BookWyrmModel):\n    ''' many-to-many through table for followers '''\n    user_subject = models.ForeignKey(\n        'User',\n        on_delete=models.PROTECT,\n        related_name='%(class)s_user_subject'\n    )\n    user_object = models.ForeignKey(\n        'User',\n        on_delete=models.PROTECT,\n        related_name='%(class)s_user_object'\n    )\n\n    class Meta:\n        ''' relationships should be unique '''\n        abstract = True\n        constraints = [\n            models.UniqueConstraint(\n                fields=['user_subject', 'user_object'],\n                name='%(class)s_unique'\n            ),\n            models.CheckConstraint(\n                check=~models.Q(user_subject=models.F('user_object')),\n                name='%(class)s_no_self'\n            )\n        ]\n\n    activity_mappings = [\n        ActivityMapping('id', 'remote_id'),\n        ActivityMapping('actor', 'user_subject'),\n        ActivityMapping('object', 'user_object'),\n    ]\n    activity_serializer = activitypub.Follow\n\n    def get_remote_id(self, status=None):\n        ''' use shelf identifier in remote_id '''\n        status = status or 'follows'\n        base_path = self.user_subject.remote_id\n        return '%s#%s/%d' % (base_path, status, self.id)\n\n\n    def to_accept_activity(self):\n        ''' generate an Accept for this follow request '''\n        return activitypub.Accept(\n            id=self.get_remote_id(status='accepts'),\n            actor=self.user_object.remote_id,\n            object=self.to_activity()\n        ).serialize()\n\n\n    def to_reject_activity(self):\n        ''' generate an Accept for this follow request '''\n        return activitypub.Reject(\n            id=self.get_remote_id(status='rejects'),\n            actor=self.user_object.remote_id,\n            object=self.to_activity()\n        ).serialize()\n\n\nclass UserFollows(UserRelationship):\n    ''' Following a user '''\n    status = 'follows'\n\n    @classmethod\n    def from_request(cls, follow_request):\n        ''' converts a follow request into a follow relationship '''\n        return cls(\n            user_subject=follow_request.user_subject,\n            user_object=follow_request.user_object,\n            remote_id=follow_request.remote_id,\n        )\n\n\nclass UserFollowRequest(UserRelationship):\n    ''' following a user requires manual or automatic confirmation '''\n    status = 'follow_request'\n\n\nclass UserBlocks(UserRelationship):\n    ''' prevent another user from following you and seeing your posts '''\n    # TODO: not implemented\n    status = 'blocks'\n", "path": "bookwyrm/models/relationship.py"}]}