prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Race conditions in muting topics and users
  Our pattern in [muting topics](https://github.com/zulip/zulip/blob/b4075b78eb6e128bce7ef3d36b86d176ef2ecfa5/zerver/views/muting.py#L39-L42) is to check if the topic is muted, and if not then to add a row:
  ```py3
      if topic_is_muted(user_profile, stream.id, topic_name):
          raise JsonableError(_("Topic already muted"))
  
      do_mute_topic(user_profile, stream, topic_name, date_muted)
      return json_success()
  ```
  
  This pattern is inherently prone to race conditions.  Luckily, we catch those due to database constraints, in the form of `UserTopic.objects.create` raising an IntegrityError, but those bubble up as 500's, not 400's.
  
  We should catch those IntegrityError's and re-raise them as `JsonableError(_("Topic already muted"))`.  That applies to the mute-topic codepath, as well as the mute-user codepath.
  
  Though it doesn't affect correctness in this case, since the duplicate row is the first database change operation, these actions should be done inside of transactions.
  
  Un-muting is technically also subject to this race, though it doesn't matter -- both processes calling `.delete()` on the same object is a mostly-silent no-op for the second process.
  
  </issue>
  <code>
  [start of zerver/views/muting.py]
  1 import datetime
  2 from typing import Optional
  3 
  4 from django.http import HttpRequest, HttpResponse
  5 from django.utils.timezone import now as timezone_now
  6 from django.utils.translation import gettext as _
  7 
  8 from zerver.lib.actions import do_mute_topic, do_mute_user, do_unmute_topic, do_unmute_user
  9 from zerver.lib.exceptions import JsonableError
  10 from zerver.lib.request import REQ, has_request_variables
  11 from zerver.lib.response import json_success
  12 from zerver.lib.streams import (
  13     access_stream_by_id,
  14     access_stream_by_name,
  15     access_stream_for_unmute_topic_by_id,
  16     access_stream_for_unmute_topic_by_name,
  17     check_for_exactly_one_stream_arg,
  18 )
  19 from zerver.lib.topic_mutes import topic_is_muted
  20 from zerver.lib.user_mutes import get_mute_object
  21 from zerver.lib.users import access_user_by_id
  22 from zerver.lib.validator import check_int
  23 from zerver.models import UserProfile
  24 
  25 
  26 def mute_topic(
  27     user_profile: UserProfile,
  28     stream_id: Optional[int],
  29     stream_name: Optional[str],
  30     topic_name: str,
  31     date_muted: datetime.datetime,
  32 ) -> None:
  33     if stream_name is not None:
  34         (stream, sub) = access_stream_by_name(user_profile, stream_name)
  35     else:
  36         assert stream_id is not None
  37         (stream, sub) = access_stream_by_id(user_profile, stream_id)
  38 
  39     if topic_is_muted(user_profile, stream.id, topic_name):
  40         raise JsonableError(_("Topic already muted"))
  41 
  42     do_mute_topic(user_profile, stream, topic_name, date_muted)
  43 
  44 
  45 def unmute_topic(
  46     user_profile: UserProfile,
  47     stream_id: Optional[int],
  48     stream_name: Optional[str],
  49     topic_name: str,
  50 ) -> None:
  51     error = _("Topic is not muted")
  52 
  53     if stream_name is not None:
  54         stream = access_stream_for_unmute_topic_by_name(user_profile, stream_name, error)
  55     else:
  56         assert stream_id is not None
  57         stream = access_stream_for_unmute_topic_by_id(user_profile, stream_id, error)
  58 
  59     do_unmute_topic(user_profile, stream, topic_name)
  60 
  61 
  62 @has_request_variables
  63 def update_muted_topic(
  64     request: HttpRequest,
  65     user_profile: UserProfile,
  66     stream_id: Optional[int] = REQ(json_validator=check_int, default=None),
  67     stream: Optional[str] = REQ(default=None),
  68     topic: str = REQ(),
  69     op: str = REQ(),
  70 ) -> HttpResponse:
  71 
  72     check_for_exactly_one_stream_arg(stream_id=stream_id, stream=stream)
  73 
  74     if op == "add":
  75         mute_topic(
  76             user_profile=user_profile,
  77             stream_id=stream_id,
  78             stream_name=stream,
  79             topic_name=topic,
  80             date_muted=timezone_now(),
  81         )
  82         return json_success(request)
  83     elif op == "remove":
  84         unmute_topic(
  85             user_profile=user_profile,
  86             stream_id=stream_id,
  87             stream_name=stream,
  88             topic_name=topic,
  89         )
  90         return json_success(request)
  91 
  92 
  93 def mute_user(request: HttpRequest, user_profile: UserProfile, muted_user_id: int) -> HttpResponse:
  94     if user_profile.id == muted_user_id:
  95         raise JsonableError(_("Cannot mute self"))
  96 
  97     muted_user = access_user_by_id(
  98         user_profile, muted_user_id, allow_bots=False, allow_deactivated=True, for_admin=False
  99     )
  100     date_muted = timezone_now()
  101 
  102     if get_mute_object(user_profile, muted_user) is not None:
  103         raise JsonableError(_("User already muted"))
  104 
  105     do_mute_user(user_profile, muted_user, date_muted)
  106     return json_success(request)
  107 
  108 
  109 def unmute_user(
  110     request: HttpRequest, user_profile: UserProfile, muted_user_id: int
  111 ) -> HttpResponse:
  112     muted_user = access_user_by_id(
  113         user_profile, muted_user_id, allow_bots=False, allow_deactivated=True, for_admin=False
  114     )
  115     mute_object = get_mute_object(user_profile, muted_user)
  116 
  117     if mute_object is None:
  118         raise JsonableError(_("User is not muted"))
  119 
  120     do_unmute_user(mute_object)
  121     return json_success(request)
  122
  [end of zerver/views/muting.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/zerver/views/muting.py b/zerver/views/muting.py
  --- a/zerver/views/muting.py
  +++ b/zerver/views/muting.py
  @@ -1,6 +1,7 @@
   import datetime
   from typing import Optional
   
  +from django.db import IntegrityError
   from django.http import HttpRequest, HttpResponse
   from django.utils.timezone import now as timezone_now
   from django.utils.translation import gettext as _
  @@ -39,7 +40,10 @@
       if topic_is_muted(user_profile, stream.id, topic_name):
           raise JsonableError(_("Topic already muted"))
   
  -    do_mute_topic(user_profile, stream, topic_name, date_muted)
  +    try:
  +        do_mute_topic(user_profile, stream, topic_name, date_muted)
  +    except IntegrityError:
  +        raise JsonableError(_("Topic already muted"))
   
   
   def unmute_topic(
  
verification_info: {"golden_diff": "diff --git a/zerver/views/muting.py b/zerver/views/muting.py\n--- a/zerver/views/muting.py\n+++ b/zerver/views/muting.py\n@@ -1,6 +1,7 @@\n import datetime\n from typing import Optional\n \n+from django.db import IntegrityError\n from django.http import HttpRequest, HttpResponse\n from django.utils.timezone import now as timezone_now\n from django.utils.translation import gettext as _\n@@ -39,7 +40,10 @@\n     if topic_is_muted(user_profile, stream.id, topic_name):\n         raise JsonableError(_(\"Topic already muted\"))\n \n-    do_mute_topic(user_profile, stream, topic_name, date_muted)\n+    try:\n+        do_mute_topic(user_profile, stream, topic_name, date_muted)\n+    except IntegrityError:\n+        raise JsonableError(_(\"Topic already muted\"))\n \n \n def unmute_topic(\n", "issue": "Race conditions in muting topics and users\nOur pattern in [muting topics](https://github.com/zulip/zulip/blob/b4075b78eb6e128bce7ef3d36b86d176ef2ecfa5/zerver/views/muting.py#L39-L42) is to check if the topic is muted, and if not then to add a row:\r\n```py3\r\n    if topic_is_muted(user_profile, stream.id, topic_name):\r\n        raise JsonableError(_(\"Topic already muted\"))\r\n\r\n    do_mute_topic(user_profile, stream, topic_name, date_muted)\r\n    return json_success()\r\n```\r\n\r\nThis pattern is inherently prone to race conditions.  Luckily, we catch those due to database constraints, in the form of `UserTopic.objects.create` raising an IntegrityError, but those bubble up as 500's, not 400's.\r\n\r\nWe should catch those IntegrityError's and re-raise them as `JsonableError(_(\"Topic already muted\"))`.  That applies to the mute-topic codepath, as well as the mute-user codepath.\r\n\r\nThough it doesn't affect correctness in this case, since the duplicate row is the first database change operation, these actions should be done inside of transactions.\r\n\r\nUn-muting is technically also subject to this race, though it doesn't matter -- both processes calling `.delete()` on the same object is a mostly-silent no-op for the second process.\n", "before_files": [{"content": "import datetime\nfrom typing import Optional\n\nfrom django.http import HttpRequest, HttpResponse\nfrom django.utils.timezone import now as timezone_now\nfrom django.utils.translation import gettext as _\n\nfrom zerver.lib.actions import do_mute_topic, do_mute_user, do_unmute_topic, do_unmute_user\nfrom zerver.lib.exceptions import JsonableError\nfrom zerver.lib.request import REQ, has_request_variables\nfrom zerver.lib.response import json_success\nfrom zerver.lib.streams import (\n    access_stream_by_id,\n    access_stream_by_name,\n    access_stream_for_unmute_topic_by_id,\n    access_stream_for_unmute_topic_by_name,\n    check_for_exactly_one_stream_arg,\n)\nfrom zerver.lib.topic_mutes import topic_is_muted\nfrom zerver.lib.user_mutes import get_mute_object\nfrom zerver.lib.users import access_user_by_id\nfrom zerver.lib.validator import check_int\nfrom zerver.models import UserProfile\n\n\ndef mute_topic(\n    user_profile: UserProfile,\n    stream_id: Optional[int],\n    stream_name: Optional[str],\n    topic_name: str,\n    date_muted: datetime.datetime,\n) -> None:\n    if stream_name is not None:\n        (stream, sub) = access_stream_by_name(user_profile, stream_name)\n    else:\n        assert stream_id is not None\n        (stream, sub) = access_stream_by_id(user_profile, stream_id)\n\n    if topic_is_muted(user_profile, stream.id, topic_name):\n        raise JsonableError(_(\"Topic already muted\"))\n\n    do_mute_topic(user_profile, stream, topic_name, date_muted)\n\n\ndef unmute_topic(\n    user_profile: UserProfile,\n    stream_id: Optional[int],\n    stream_name: Optional[str],\n    topic_name: str,\n) -> None:\n    error = _(\"Topic is not muted\")\n\n    if stream_name is not None:\n        stream = access_stream_for_unmute_topic_by_name(user_profile, stream_name, error)\n    else:\n        assert stream_id is not None\n        stream = access_stream_for_unmute_topic_by_id(user_profile, stream_id, error)\n\n    do_unmute_topic(user_profile, stream, topic_name)\n\n\n@has_request_variables\ndef update_muted_topic(\n    request: HttpRequest,\n    user_profile: UserProfile,\n    stream_id: Optional[int] = REQ(json_validator=check_int, default=None),\n    stream: Optional[str] = REQ(default=None),\n    topic: str = REQ(),\n    op: str = REQ(),\n) -> HttpResponse:\n\n    check_for_exactly_one_stream_arg(stream_id=stream_id, stream=stream)\n\n    if op == \"add\":\n        mute_topic(\n            user_profile=user_profile,\n            stream_id=stream_id,\n            stream_name=stream,\n            topic_name=topic,\n            date_muted=timezone_now(),\n        )\n        return json_success(request)\n    elif op == \"remove\":\n        unmute_topic(\n            user_profile=user_profile,\n            stream_id=stream_id,\n            stream_name=stream,\n            topic_name=topic,\n        )\n        return json_success(request)\n\n\ndef mute_user(request: HttpRequest, user_profile: UserProfile, muted_user_id: int) -> HttpResponse:\n    if user_profile.id == muted_user_id:\n        raise JsonableError(_(\"Cannot mute self\"))\n\n    muted_user = access_user_by_id(\n        user_profile, muted_user_id, allow_bots=False, allow_deactivated=True, for_admin=False\n    )\n    date_muted = timezone_now()\n\n    if get_mute_object(user_profile, muted_user) is not None:\n        raise JsonableError(_(\"User already muted\"))\n\n    do_mute_user(user_profile, muted_user, date_muted)\n    return json_success(request)\n\n\ndef unmute_user(\n    request: HttpRequest, user_profile: UserProfile, muted_user_id: int\n) -> HttpResponse:\n    muted_user = access_user_by_id(\n        user_profile, muted_user_id, allow_bots=False, allow_deactivated=True, for_admin=False\n    )\n    mute_object = get_mute_object(user_profile, muted_user)\n\n    if mute_object is None:\n        raise JsonableError(_(\"User is not muted\"))\n\n    do_unmute_user(mute_object)\n    return json_success(request)\n", "path": "zerver/views/muting.py"}]}