We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
link formatting not working properly
I made a markdown link, but the "<a href" part was trimmed and garbled html remained

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bookwyrm/views/status.py`
Content:
```
1 ''' what are we here for if not for posting '''
2 import re
3 from django.contrib.auth.decorators import login_required
4 from django.http import HttpResponseBadRequest
5 from django.shortcuts import get_object_or_404, redirect
6 from django.utils.decorators import method_decorator
7 from django.views import View
8 from markdown import markdown
9 
10 from bookwyrm import forms, models
11 from bookwyrm.sanitize_html import InputHtmlParser
12 from bookwyrm.settings import DOMAIN
13 from bookwyrm.status import create_notification, delete_status
14 from bookwyrm.utils import regex
15 from .helpers import handle_remote_webfinger
16 
17 
18 # pylint: disable= no-self-use
19 @method_decorator(login_required, name='dispatch')
20 class CreateStatus(View):
21     ''' the view for *posting* '''
22     def post(self, request, status_type):
23         ''' create  status of whatever type '''
24         status_type = status_type[0].upper() + status_type[1:]
25 
26         try:
27             form = getattr(forms, '%sForm' % status_type)(request.POST)
28         except AttributeError:
29             return HttpResponseBadRequest()
30         if not form.is_valid():
31             return redirect(request.headers.get('Referer', '/'))
32 
33         status = form.save(commit=False)
34         if not status.sensitive and status.content_warning:
35             # the cw text field remains populated when you click "remove"
36             status.content_warning = None
37         status.save(broadcast=False)
38 
39         # inspect the text for user tags
40         content = status.content
41         for (mention_text, mention_user) in find_mentions(content):
42             # add them to status mentions fk
43             status.mention_users.add(mention_user)
44 
45             # turn the mention into a link
46             content = re.sub(
47                 r'%s([^@]|$)' % mention_text,
48                 r'<a href="%s">%s</a>\g<1>' % \
49                     (mention_user.remote_id, mention_text),
50                 content)
51 
52         # add reply parent to mentions and notify
53         if status.reply_parent:
54             status.mention_users.add(status.reply_parent.user)
55 
56             if status.reply_parent.user.local:
57                 create_notification(
58                     status.reply_parent.user,
59                     'REPLY',
60                     related_user=request.user,
61                     related_status=status
62                 )
63 
64         # deduplicate mentions
65         status.mention_users.set(set(status.mention_users.all()))
66         # create mention notifications
67         for mention_user in status.mention_users.all():
68             if status.reply_parent and mention_user == status.reply_parent.user:
69                 continue
70             if mention_user.local:
71                 create_notification(
72                     mention_user,
73                     'MENTION',
74                     related_user=request.user,
75                     related_status=status
76                 )
77 
78         # don't apply formatting to generated notes
79         if not isinstance(status, models.GeneratedNote):
80             status.content = to_markdown(content)
81         # do apply formatting to quotes
82         if hasattr(status, 'quote'):
83             status.quote = to_markdown(status.quote)
84 
85         status.save(created=True)
86         return redirect(request.headers.get('Referer', '/'))
87 
88 
89 class DeleteStatus(View):
90     ''' tombstone that bad boy '''
91     def post(self, request, status_id):
92         ''' delete and tombstone a status '''
93         status = get_object_or_404(models.Status, id=status_id)
94 
95         # don't let people delete other people's statuses
96         if status.user != request.user:
97             return HttpResponseBadRequest()
98 
99         # perform deletion
100         delete_status(status)
101         return redirect(request.headers.get('Referer', '/'))
102 
103 def find_mentions(content):
104     ''' detect @mentions in raw status content '''
105     for match in re.finditer(regex.strict_username, content):
106         username = match.group().strip().split('@')[1:]
107         if len(username) == 1:
108             # this looks like a local user (@user), fill in the domain
109             username.append(DOMAIN)
110         username = '@'.join(username)
111 
112         mention_user = handle_remote_webfinger(username)
113         if not mention_user:
114             # we can ignore users we don't know about
115             continue
116         yield (match.group(), mention_user)
117 
118 
119 def format_links(content):
120     ''' detect and format links '''
121     return re.sub(
122         r'([^(href=")]|^|\()(https?:\/\/(%s([\w\.\-_\/+&\?=:;,])*))' % \
123                 regex.domain,
124         r'\g<1><a href="\g<2>">\g<3></a>',
125         content)
126 
127 def to_markdown(content):
128     ''' catch links and convert to markdown '''
129     content = format_links(content)
130     content = markdown(content)
131     # sanitize resulting html
132     sanitizer = InputHtmlParser()
133     sanitizer.feed(content)
134     return sanitizer.get_output()
135
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py
--- a/bookwyrm/views/status.py
+++ b/bookwyrm/views/status.py
@@ -48,7 +48,6 @@
                 r'<a href="%s">%s</a>\g<1>' % \
                     (mention_user.remote_id, mention_text),
                 content)
-
         # add reply parent to mentions and notify
         if status.reply_parent:
             status.mention_users.add(status.reply_parent.user)
@@ -126,8 +125,8 @@
 
 def to_markdown(content):
     ''' catch links and convert to markdown '''
-    content = format_links(content)
     content = markdown(content)
+    content = format_links(content)
     # sanitize resulting html
     sanitizer = InputHtmlParser()
     sanitizer.feed(content)

{"golden_diff": "diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py\n--- a/bookwyrm/views/status.py\n+++ b/bookwyrm/views/status.py\n@@ -48,7 +48,6 @@\n                 r'<a href=\"%s\">%s</a>\\g<1>' % \\\n                     (mention_user.remote_id, mention_text),\n                 content)\n-\n         # add reply parent to mentions and notify\n         if status.reply_parent:\n             status.mention_users.add(status.reply_parent.user)\n@@ -126,8 +125,8 @@\n \n def to_markdown(content):\n     ''' catch links and convert to markdown '''\n-    content = format_links(content)\n     content = markdown(content)\n+    content = format_links(content)\n     # sanitize resulting html\n     sanitizer = InputHtmlParser()\n     sanitizer.feed(content)\n", "issue": "link formatting not working properly\nI made a markdown link, but the \"<a href\" part was trimmed and garbled html remained\n", "before_files": [{"content": "''' what are we here for if not for posting '''\nimport re\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import HttpResponseBadRequest\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils.decorators import method_decorator\nfrom django.views import View\nfrom markdown import markdown\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.sanitize_html import InputHtmlParser\nfrom bookwyrm.settings import DOMAIN\nfrom bookwyrm.status import create_notification, delete_status\nfrom bookwyrm.utils import regex\nfrom .helpers import handle_remote_webfinger\n\n\n# pylint: disable= no-self-use\n@method_decorator(login_required, name='dispatch')\nclass CreateStatus(View):\n    ''' the view for *posting* '''\n    def post(self, request, status_type):\n        ''' create  status of whatever type '''\n        status_type = status_type[0].upper() + status_type[1:]\n\n        try:\n            form = getattr(forms, '%sForm' % status_type)(request.POST)\n        except AttributeError:\n            return HttpResponseBadRequest()\n        if not form.is_valid():\n            return redirect(request.headers.get('Referer', '/'))\n\n        status = form.save(commit=False)\n        if not status.sensitive and status.content_warning:\n            # the cw text field remains populated when you click \"remove\"\n            status.content_warning = None\n        status.save(broadcast=False)\n\n        # inspect the text for user tags\n        content = status.content\n        for (mention_text, mention_user) in find_mentions(content):\n            # add them to status mentions fk\n            status.mention_users.add(mention_user)\n\n            # turn the mention into a link\n            content = re.sub(\n                r'%s([^@]|$)' % mention_text,\n                r'<a href=\"%s\">%s</a>\\g<1>' % \\\n                    (mention_user.remote_id, mention_text),\n                content)\n\n        # add reply parent to mentions and notify\n        if status.reply_parent:\n            status.mention_users.add(status.reply_parent.user)\n\n            if status.reply_parent.user.local:\n                create_notification(\n                    status.reply_parent.user,\n                    'REPLY',\n                    related_user=request.user,\n                    related_status=status\n                )\n\n        # deduplicate mentions\n        status.mention_users.set(set(status.mention_users.all()))\n        # create mention notifications\n        for mention_user in status.mention_users.all():\n            if status.reply_parent and mention_user == status.reply_parent.user:\n                continue\n            if mention_user.local:\n                create_notification(\n                    mention_user,\n                    'MENTION',\n                    related_user=request.user,\n                    related_status=status\n                )\n\n        # don't apply formatting to generated notes\n        if not isinstance(status, models.GeneratedNote):\n            status.content = to_markdown(content)\n        # do apply formatting to quotes\n        if hasattr(status, 'quote'):\n            status.quote = to_markdown(status.quote)\n\n        status.save(created=True)\n        return redirect(request.headers.get('Referer', '/'))\n\n\nclass DeleteStatus(View):\n    ''' tombstone that bad boy '''\n    def post(self, request, status_id):\n        ''' delete and tombstone a status '''\n        status = get_object_or_404(models.Status, id=status_id)\n\n        # don't let people delete other people's statuses\n        if status.user != request.user:\n            return HttpResponseBadRequest()\n\n        # perform deletion\n        delete_status(status)\n        return redirect(request.headers.get('Referer', '/'))\n\ndef find_mentions(content):\n    ''' detect @mentions in raw status content '''\n    for match in re.finditer(regex.strict_username, content):\n        username = match.group().strip().split('@')[1:]\n        if len(username) == 1:\n            # this looks like a local user (@user), fill in the domain\n            username.append(DOMAIN)\n        username = '@'.join(username)\n\n        mention_user = handle_remote_webfinger(username)\n        if not mention_user:\n            # we can ignore users we don't know about\n            continue\n        yield (match.group(), mention_user)\n\n\ndef format_links(content):\n    ''' detect and format links '''\n    return re.sub(\n        r'([^(href=\")]|^|\\()(https?:\\/\\/(%s([\\w\\.\\-_\\/+&\\?=:;,])*))' % \\\n                regex.domain,\n        r'\\g<1><a href=\"\\g<2>\">\\g<3></a>',\n        content)\n\ndef to_markdown(content):\n    ''' catch links and convert to markdown '''\n    content = format_links(content)\n    content = markdown(content)\n    # sanitize resulting html\n    sanitizer = InputHtmlParser()\n    sanitizer.feed(content)\n    return sanitizer.get_output()\n", "path": "bookwyrm/views/status.py"}], "after_files": [{"content": "''' what are we here for if not for posting '''\nimport re\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import HttpResponseBadRequest\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils.decorators import method_decorator\nfrom django.views import View\nfrom markdown import markdown\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.sanitize_html import InputHtmlParser\nfrom bookwyrm.settings import DOMAIN\nfrom bookwyrm.status import create_notification, delete_status\nfrom bookwyrm.utils import regex\nfrom .helpers import handle_remote_webfinger\n\n\n# pylint: disable= no-self-use\n@method_decorator(login_required, name='dispatch')\nclass CreateStatus(View):\n    ''' the view for *posting* '''\n    def post(self, request, status_type):\n        ''' create  status of whatever type '''\n        status_type = status_type[0].upper() + status_type[1:]\n\n        try:\n            form = getattr(forms, '%sForm' % status_type)(request.POST)\n        except AttributeError:\n            return HttpResponseBadRequest()\n        if not form.is_valid():\n            return redirect(request.headers.get('Referer', '/'))\n\n        status = form.save(commit=False)\n        if not status.sensitive and status.content_warning:\n            # the cw text field remains populated when you click \"remove\"\n            status.content_warning = None\n        status.save(broadcast=False)\n\n        # inspect the text for user tags\n        content = status.content\n        for (mention_text, mention_user) in find_mentions(content):\n            # add them to status mentions fk\n            status.mention_users.add(mention_user)\n\n            # turn the mention into a link\n            content = re.sub(\n                r'%s([^@]|$)' % mention_text,\n                r'<a href=\"%s\">%s</a>\\g<1>' % \\\n                    (mention_user.remote_id, mention_text),\n                content)\n        # add reply parent to mentions and notify\n        if status.reply_parent:\n            status.mention_users.add(status.reply_parent.user)\n\n            if status.reply_parent.user.local:\n                create_notification(\n                    status.reply_parent.user,\n                    'REPLY',\n                    related_user=request.user,\n                    related_status=status\n                )\n\n        # deduplicate mentions\n        status.mention_users.set(set(status.mention_users.all()))\n        # create mention notifications\n        for mention_user in status.mention_users.all():\n            if status.reply_parent and mention_user == status.reply_parent.user:\n                continue\n            if mention_user.local:\n                create_notification(\n                    mention_user,\n                    'MENTION',\n                    related_user=request.user,\n                    related_status=status\n                )\n\n        # don't apply formatting to generated notes\n        if not isinstance(status, models.GeneratedNote):\n            status.content = to_markdown(content)\n        # do apply formatting to quotes\n        if hasattr(status, 'quote'):\n            status.quote = to_markdown(status.quote)\n\n        status.save(created=True)\n        return redirect(request.headers.get('Referer', '/'))\n\n\nclass DeleteStatus(View):\n    ''' tombstone that bad boy '''\n    def post(self, request, status_id):\n        ''' delete and tombstone a status '''\n        status = get_object_or_404(models.Status, id=status_id)\n\n        # don't let people delete other people's statuses\n        if status.user != request.user:\n            return HttpResponseBadRequest()\n\n        # perform deletion\n        delete_status(status)\n        return redirect(request.headers.get('Referer', '/'))\n\ndef find_mentions(content):\n    ''' detect @mentions in raw status content '''\n    for match in re.finditer(regex.strict_username, content):\n        username = match.group().strip().split('@')[1:]\n        if len(username) == 1:\n            # this looks like a local user (@user), fill in the domain\n            username.append(DOMAIN)\n        username = '@'.join(username)\n\n        mention_user = handle_remote_webfinger(username)\n        if not mention_user:\n            # we can ignore users we don't know about\n            continue\n        yield (match.group(), mention_user)\n\n\ndef format_links(content):\n    ''' detect and format links '''\n    return re.sub(\n        r'([^(href=\")]|^|\\()(https?:\\/\\/(%s([\\w\\.\\-_\\/+&\\?=:;,])*))' % \\\n                regex.domain,\n        r'\\g<1><a href=\"\\g<2>\">\\g<3></a>',\n        content)\n\ndef to_markdown(content):\n    ''' catch links and convert to markdown '''\n    content = markdown(content)\n    content = format_links(content)\n    # sanitize resulting html\n    sanitizer = InputHtmlParser()\n    sanitizer.feed(content)\n    return sanitizer.get_output()\n", "path": "bookwyrm/views/status.py"}]}