We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Feature request - block quote formatting in reviews
I published [a review](https://bookwyrm.social/user/darius/review/14497) just now with a markdown-style block quote in it. The second-to-last paragraph is formatted, at least when I wrote it in the dialog box, like this:

```
> "I was expecting to go to prison for the rest of my life," Ellsberg wryly said later, "and Ithiel wanted to know whether I understood that I'd never get another dollar from the federal government."
```

But it renders as regular text. I'm guessing a lot of reviewers will want to excerpt their books, so block quotes seem like a good thing to include!

I would expect it to render more like it does here on Github:

> "I was expecting to go to prison for the rest of my life," Ellsberg wryly said later, "and Ithiel wanted to know whether I understood that I'd never get another dollar from the federal government."

--- 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/sanitize_html.py`
Content:
```
1 ''' html parser to clean up incoming text from unknown sources '''
2 from html.parser import HTMLParser
3 
4 class InputHtmlParser(HTMLParser):#pylint: disable=abstract-method
5     ''' Removes any html that isn't allowed_tagsed from a block '''
6 
7     def __init__(self):
8         HTMLParser.__init__(self)
9         self.allowed_tags = [
10             'p', 'br',
11             'b', 'i', 'strong', 'em', 'pre',
12             'a', 'span', 'ul', 'ol', 'li'
13         ]
14         self.tag_stack = []
15         self.output = []
16         # if the html appears invalid, we just won't allow any at all
17         self.allow_html = True
18 
19 
20     def handle_starttag(self, tag, attrs):
21         ''' check if the tag is valid '''
22         if self.allow_html and tag in self.allowed_tags:
23             self.output.append(('tag', self.get_starttag_text()))
24             self.tag_stack.append(tag)
25         else:
26             self.output.append(('data', ''))
27 
28 
29     def handle_endtag(self, tag):
30         ''' keep the close tag '''
31         if not self.allow_html or tag not in self.allowed_tags:
32             self.output.append(('data', ''))
33             return
34 
35         if not self.tag_stack or self.tag_stack[-1] != tag:
36             # the end tag doesn't match the most recent start tag
37             self.allow_html = False
38             self.output.append(('data', ''))
39             return
40 
41         self.tag_stack = self.tag_stack[:-1]
42         self.output.append(('tag', '</%s>' % tag))
43 
44 
45     def handle_data(self, data):
46         ''' extract the answer, if we're in an answer tag '''
47         self.output.append(('data', data))
48 
49 
50     def get_output(self):
51         ''' convert the output from a list of tuples to a string '''
52         if self.tag_stack:
53             self.allow_html = False
54         if not self.allow_html:
55             return ''.join(v for (k, v) in self.output if k == 'data')
56         return ''.join(v for (k, v) in self.output)
57
```
--- 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/sanitize_html.py b/bookwyrm/sanitize_html.py
--- a/bookwyrm/sanitize_html.py
+++ b/bookwyrm/sanitize_html.py
@@ -7,7 +7,7 @@
     def __init__(self):
         HTMLParser.__init__(self)
         self.allowed_tags = [
-            'p', 'br',
+            'p', 'blockquote', 'br',
             'b', 'i', 'strong', 'em', 'pre',
             'a', 'span', 'ul', 'ol', 'li'
         ]

{"golden_diff": "diff --git a/bookwyrm/sanitize_html.py b/bookwyrm/sanitize_html.py\n--- a/bookwyrm/sanitize_html.py\n+++ b/bookwyrm/sanitize_html.py\n@@ -7,7 +7,7 @@\n     def __init__(self):\n         HTMLParser.__init__(self)\n         self.allowed_tags = [\n-            'p', 'br',\n+            'p', 'blockquote', 'br',\n             'b', 'i', 'strong', 'em', 'pre',\n             'a', 'span', 'ul', 'ol', 'li'\n         ]\n", "issue": "Feature request - block quote formatting in reviews\nI published [a review](https://bookwyrm.social/user/darius/review/14497) just now with a markdown-style block quote in it. The second-to-last paragraph is formatted, at least when I wrote it in the dialog box, like this:\r\n\r\n```\r\n> \"I was expecting to go to prison for the rest of my life,\" Ellsberg wryly said later, \"and Ithiel wanted to know whether I understood that I'd never get another dollar from the federal government.\"\r\n```\r\n\r\nBut it renders as regular text. I'm guessing a lot of reviewers will want to excerpt their books, so block quotes seem like a good thing to include!\r\n\r\nI would expect it to render more like it does here on Github:\r\n\r\n> \"I was expecting to go to prison for the rest of my life,\" Ellsberg wryly said later, \"and Ithiel wanted to know whether I understood that I'd never get another dollar from the federal government.\"\n", "before_files": [{"content": "''' html parser to clean up incoming text from unknown sources '''\nfrom html.parser import HTMLParser\n\nclass InputHtmlParser(HTMLParser):#pylint: disable=abstract-method\n    ''' Removes any html that isn't allowed_tagsed from a block '''\n\n    def __init__(self):\n        HTMLParser.__init__(self)\n        self.allowed_tags = [\n            'p', 'br',\n            'b', 'i', 'strong', 'em', 'pre',\n            'a', 'span', 'ul', 'ol', 'li'\n        ]\n        self.tag_stack = []\n        self.output = []\n        # if the html appears invalid, we just won't allow any at all\n        self.allow_html = True\n\n\n    def handle_starttag(self, tag, attrs):\n        ''' check if the tag is valid '''\n        if self.allow_html and tag in self.allowed_tags:\n            self.output.append(('tag', self.get_starttag_text()))\n            self.tag_stack.append(tag)\n        else:\n            self.output.append(('data', ''))\n\n\n    def handle_endtag(self, tag):\n        ''' keep the close tag '''\n        if not self.allow_html or tag not in self.allowed_tags:\n            self.output.append(('data', ''))\n            return\n\n        if not self.tag_stack or self.tag_stack[-1] != tag:\n            # the end tag doesn't match the most recent start tag\n            self.allow_html = False\n            self.output.append(('data', ''))\n            return\n\n        self.tag_stack = self.tag_stack[:-1]\n        self.output.append(('tag', '</%s>' % tag))\n\n\n    def handle_data(self, data):\n        ''' extract the answer, if we're in an answer tag '''\n        self.output.append(('data', data))\n\n\n    def get_output(self):\n        ''' convert the output from a list of tuples to a string '''\n        if self.tag_stack:\n            self.allow_html = False\n        if not self.allow_html:\n            return ''.join(v for (k, v) in self.output if k == 'data')\n        return ''.join(v for (k, v) in self.output)\n", "path": "bookwyrm/sanitize_html.py"}], "after_files": [{"content": "''' html parser to clean up incoming text from unknown sources '''\nfrom html.parser import HTMLParser\n\nclass InputHtmlParser(HTMLParser):#pylint: disable=abstract-method\n    ''' Removes any html that isn't allowed_tagsed from a block '''\n\n    def __init__(self):\n        HTMLParser.__init__(self)\n        self.allowed_tags = [\n            'p', 'blockquote', 'br',\n            'b', 'i', 'strong', 'em', 'pre',\n            'a', 'span', 'ul', 'ol', 'li'\n        ]\n        self.tag_stack = []\n        self.output = []\n        # if the html appears invalid, we just won't allow any at all\n        self.allow_html = True\n\n\n    def handle_starttag(self, tag, attrs):\n        ''' check if the tag is valid '''\n        if self.allow_html and tag in self.allowed_tags:\n            self.output.append(('tag', self.get_starttag_text()))\n            self.tag_stack.append(tag)\n        else:\n            self.output.append(('data', ''))\n\n\n    def handle_endtag(self, tag):\n        ''' keep the close tag '''\n        if not self.allow_html or tag not in self.allowed_tags:\n            self.output.append(('data', ''))\n            return\n\n        if not self.tag_stack or self.tag_stack[-1] != tag:\n            # the end tag doesn't match the most recent start tag\n            self.allow_html = False\n            self.output.append(('data', ''))\n            return\n\n        self.tag_stack = self.tag_stack[:-1]\n        self.output.append(('tag', '</%s>' % tag))\n\n\n    def handle_data(self, data):\n        ''' extract the answer, if we're in an answer tag '''\n        self.output.append(('data', data))\n\n\n    def get_output(self):\n        ''' convert the output from a list of tuples to a string '''\n        if self.tag_stack:\n            self.allow_html = False\n        if not self.allow_html:\n            return ''.join(v for (k, v) in self.output if k == 'data')\n        return ''.join(v for (k, v) in self.output)\n", "path": "bookwyrm/sanitize_html.py"}]}