We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
not able to search for a user un-logged in
No option to search for a user without being logged in even though it says books or users in the non logged in search field 

**Screenshots**
![B1B1BF6E-685C-4981-AC1C-FD393FC5DCDA](https://user-images.githubusercontent.com/7890201/134020800-b1b6b514-35a4-4afa-829f-652d6a7028ae.png)
![C1878A19-8A29-48BC-9993-3E105F743301](https://user-images.githubusercontent.com/7890201/134020810-e0d4dfc0-ce11-44e8-b01c-f939d8146b80.png)

**Instance**
bookwyrm.social

---

**Desktop (please complete the following information):**
iOS 12, Firefox


--- 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/search.py`
Content:
```
1 """ search views"""
2 import re
3 
4 from django.contrib.postgres.search import TrigramSimilarity
5 from django.core.paginator import Paginator
6 from django.db.models.functions import Greatest
7 from django.http import JsonResponse
8 from django.template.response import TemplateResponse
9 from django.views import View
10 
11 from csp.decorators import csp_update
12 
13 from bookwyrm import models
14 from bookwyrm.connectors import connector_manager
15 from bookwyrm.book_search import search, format_search_result
16 from bookwyrm.settings import PAGE_LENGTH
17 from bookwyrm.utils import regex
18 from .helpers import is_api_request
19 from .helpers import handle_remote_webfinger
20 
21 
22 # pylint: disable= no-self-use
23 class Search(View):
24     """search users or books"""
25 
26     @csp_update(IMG_SRC="*")
27     def get(self, request):
28         """that search bar up top"""
29         if is_api_request(request):
30             return api_book_search(request)
31 
32         query = request.GET.get("q")
33         if not query:
34             return TemplateResponse(request, "search/book.html")
35 
36         search_type = request.GET.get("type")
37         if query and not search_type:
38             search_type = "user" if "@" in query else "book"
39 
40         endpoints = {
41             "book": book_search,
42             "user": user_search,
43             "list": list_search,
44         }
45         if not search_type in endpoints:
46             search_type = "book"
47 
48         return endpoints[search_type](request)
49 
50 
51 def api_book_search(request):
52     """Return books via API response"""
53     query = request.GET.get("q")
54     query = isbn_check(query)
55     min_confidence = request.GET.get("min_confidence", 0)
56     # only return local book results via json so we don't cascade
57     book_results = search(query, min_confidence=min_confidence)
58     return JsonResponse(
59         [format_search_result(r) for r in book_results[:10]], safe=False
60     )
61 
62 
63 def book_search(request):
64     """the real business is elsewhere"""
65     query = request.GET.get("q")
66     # check if query is isbn
67     query = isbn_check(query)
68     min_confidence = request.GET.get("min_confidence", 0)
69     search_remote = request.GET.get("remote", False) and request.user.is_authenticated
70 
71     # try a local-only search
72     local_results = search(query, min_confidence=min_confidence)
73     paginated = Paginator(local_results, PAGE_LENGTH)
74     page = paginated.get_page(request.GET.get("page"))
75     data = {
76         "query": query,
77         "results": page,
78         "type": "book",
79         "remote": search_remote,
80         "page_range": paginated.get_elided_page_range(
81             page.number, on_each_side=2, on_ends=1
82         ),
83     }
84     # if a logged in user requested remote results or got no local results, try remote
85     if request.user.is_authenticated and (not local_results or search_remote):
86         data["remote_results"] = connector_manager.search(
87             query, min_confidence=min_confidence
88         )
89         data["remote"] = True
90     return TemplateResponse(request, "search/book.html", data)
91 
92 
93 def user_search(request):
94     """cool kids members only user search"""
95     viewer = request.user
96     query = request.GET.get("q")
97     query = query.strip()
98     data = {"type": "user", "query": query}
99     # logged out viewers can't search users
100     if not viewer.is_authenticated:
101         return TemplateResponse(request, "search/user.html", data)
102 
103     # use webfinger for mastodon style account@domain.com username to load the user if
104     # they don't exist locally (handle_remote_webfinger will check the db)
105     if re.match(regex.FULL_USERNAME, query):
106         handle_remote_webfinger(query)
107 
108     results = (
109         models.User.viewer_aware_objects(viewer)
110         .annotate(
111             similarity=Greatest(
112                 TrigramSimilarity("username", query),
113                 TrigramSimilarity("localname", query),
114             )
115         )
116         .filter(
117             similarity__gt=0.5,
118         )
119         .order_by("-similarity")
120     )
121     paginated = Paginator(results, PAGE_LENGTH)
122     page = paginated.get_page(request.GET.get("page"))
123     data["results"] = page
124     data["page_range"] = paginated.get_elided_page_range(
125         page.number, on_each_side=2, on_ends=1
126     )
127     return TemplateResponse(request, "search/user.html", data)
128 
129 
130 def list_search(request):
131     """any relevent lists?"""
132     query = request.GET.get("q")
133     data = {"query": query, "type": "list"}
134     results = (
135         models.List.privacy_filter(
136             request.user,
137             privacy_levels=["public", "followers"],
138         )
139         .annotate(
140             similarity=Greatest(
141                 TrigramSimilarity("name", query),
142                 TrigramSimilarity("description", query),
143             )
144         )
145         .filter(
146             similarity__gt=0.1,
147         )
148         .order_by("-similarity")
149     )
150     paginated = Paginator(results, PAGE_LENGTH)
151     page = paginated.get_page(request.GET.get("page"))
152     data["results"] = page
153     data["page_range"] = paginated.get_elided_page_range(
154         page.number, on_each_side=2, on_ends=1
155     )
156     return TemplateResponse(request, "search/list.html", data)
157 
158 
159 def isbn_check(query):
160     """isbn10 or isbn13 check, if so remove separators"""
161     if query:
162         su_num = re.sub(r"(?<=\d)\D(?=\d|[xX])", "", query)
163         if len(su_num) == 13 and su_num.isdecimal():
164             # Multiply every other digit by  3
165             # Add these numbers and the other digits
166             product = sum(int(ch) for ch in su_num[::2]) + sum(
167                 int(ch) * 3 for ch in su_num[1::2]
168             )
169             if product % 10 == 0:
170                 return su_num
171         elif (
172             len(su_num) == 10
173             and su_num[:-1].isdecimal()
174             and (su_num[-1].isdecimal() or su_num[-1].lower() == "x")
175         ):
176             product = 0
177             # Iterate through code_string
178             for i in range(9):
179                 # for each character, multiply by a different decreasing number: 10 - x
180                 product = product + int(su_num[i]) * (10 - i)
181             # Handle last character
182             if su_num[9].lower() == "x":
183                 product += 10
184             else:
185                 product += int(su_num[9])
186             if product % 11 == 0:
187                 return su_num
188     return query
189
```
--- 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/search.py b/bookwyrm/views/search.py
--- a/bookwyrm/views/search.py
+++ b/bookwyrm/views/search.py
@@ -91,18 +91,15 @@
 
 
 def user_search(request):
-    """cool kids members only user search"""
+    """user search: search for a user"""
     viewer = request.user
     query = request.GET.get("q")
     query = query.strip()
     data = {"type": "user", "query": query}
-    # logged out viewers can't search users
-    if not viewer.is_authenticated:
-        return TemplateResponse(request, "search/user.html", data)
 
     # use webfinger for mastodon style account@domain.com username to load the user if
     # they don't exist locally (handle_remote_webfinger will check the db)
-    if re.match(regex.FULL_USERNAME, query):
+    if re.match(regex.FULL_USERNAME, query) and viewer.is_authenticated:
         handle_remote_webfinger(query)
 
     results = (
@@ -118,6 +115,11 @@
         )
         .order_by("-similarity")
     )
+
+    # don't expose remote users
+    if not viewer.is_authenticated:
+        results = results.filter(local=True)
+
     paginated = Paginator(results, PAGE_LENGTH)
     page = paginated.get_page(request.GET.get("page"))
     data["results"] = page

{"golden_diff": "diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py\n--- a/bookwyrm/views/search.py\n+++ b/bookwyrm/views/search.py\n@@ -91,18 +91,15 @@\n \n \n def user_search(request):\n-    \"\"\"cool kids members only user search\"\"\"\n+    \"\"\"user search: search for a user\"\"\"\n     viewer = request.user\n     query = request.GET.get(\"q\")\n     query = query.strip()\n     data = {\"type\": \"user\", \"query\": query}\n-    # logged out viewers can't search users\n-    if not viewer.is_authenticated:\n-        return TemplateResponse(request, \"search/user.html\", data)\n \n     # use webfinger for mastodon style account@domain.com username to load the user if\n     # they don't exist locally (handle_remote_webfinger will check the db)\n-    if re.match(regex.FULL_USERNAME, query):\n+    if re.match(regex.FULL_USERNAME, query) and viewer.is_authenticated:\n         handle_remote_webfinger(query)\n \n     results = (\n@@ -118,6 +115,11 @@\n         )\n         .order_by(\"-similarity\")\n     )\n+\n+    # don't expose remote users\n+    if not viewer.is_authenticated:\n+        results = results.filter(local=True)\n+\n     paginated = Paginator(results, PAGE_LENGTH)\n     page = paginated.get_page(request.GET.get(\"page\"))\n     data[\"results\"] = page\n", "issue": "not able to search for a user un-logged in\nNo option to search for a user without being logged in even though it says books or users in the non logged in search field \r\n\r\n**Screenshots**\r\n![B1B1BF6E-685C-4981-AC1C-FD393FC5DCDA](https://user-images.githubusercontent.com/7890201/134020800-b1b6b514-35a4-4afa-829f-652d6a7028ae.png)\r\n![C1878A19-8A29-48BC-9993-3E105F743301](https://user-images.githubusercontent.com/7890201/134020810-e0d4dfc0-ce11-44e8-b01c-f939d8146b80.png)\r\n\r\n**Instance**\r\nbookwyrm.social\r\n\r\n---\r\n\r\n**Desktop (please complete the following information):**\r\niOS 12, Firefox\r\n\n", "before_files": [{"content": "\"\"\" search views\"\"\"\nimport re\n\nfrom django.contrib.postgres.search import TrigramSimilarity\nfrom django.core.paginator import Paginator\nfrom django.db.models.functions import Greatest\nfrom django.http import JsonResponse\nfrom django.template.response import TemplateResponse\nfrom django.views import View\n\nfrom csp.decorators import csp_update\n\nfrom bookwyrm import models\nfrom bookwyrm.connectors import connector_manager\nfrom bookwyrm.book_search import search, format_search_result\nfrom bookwyrm.settings import PAGE_LENGTH\nfrom bookwyrm.utils import regex\nfrom .helpers import is_api_request\nfrom .helpers import handle_remote_webfinger\n\n\n# pylint: disable= no-self-use\nclass Search(View):\n    \"\"\"search users or books\"\"\"\n\n    @csp_update(IMG_SRC=\"*\")\n    def get(self, request):\n        \"\"\"that search bar up top\"\"\"\n        if is_api_request(request):\n            return api_book_search(request)\n\n        query = request.GET.get(\"q\")\n        if not query:\n            return TemplateResponse(request, \"search/book.html\")\n\n        search_type = request.GET.get(\"type\")\n        if query and not search_type:\n            search_type = \"user\" if \"@\" in query else \"book\"\n\n        endpoints = {\n            \"book\": book_search,\n            \"user\": user_search,\n            \"list\": list_search,\n        }\n        if not search_type in endpoints:\n            search_type = \"book\"\n\n        return endpoints[search_type](request)\n\n\ndef api_book_search(request):\n    \"\"\"Return books via API response\"\"\"\n    query = request.GET.get(\"q\")\n    query = isbn_check(query)\n    min_confidence = request.GET.get(\"min_confidence\", 0)\n    # only return local book results via json so we don't cascade\n    book_results = search(query, min_confidence=min_confidence)\n    return JsonResponse(\n        [format_search_result(r) for r in book_results[:10]], safe=False\n    )\n\n\ndef book_search(request):\n    \"\"\"the real business is elsewhere\"\"\"\n    query = request.GET.get(\"q\")\n    # check if query is isbn\n    query = isbn_check(query)\n    min_confidence = request.GET.get(\"min_confidence\", 0)\n    search_remote = request.GET.get(\"remote\", False) and request.user.is_authenticated\n\n    # try a local-only search\n    local_results = search(query, min_confidence=min_confidence)\n    paginated = Paginator(local_results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data = {\n        \"query\": query,\n        \"results\": page,\n        \"type\": \"book\",\n        \"remote\": search_remote,\n        \"page_range\": paginated.get_elided_page_range(\n            page.number, on_each_side=2, on_ends=1\n        ),\n    }\n    # if a logged in user requested remote results or got no local results, try remote\n    if request.user.is_authenticated and (not local_results or search_remote):\n        data[\"remote_results\"] = connector_manager.search(\n            query, min_confidence=min_confidence\n        )\n        data[\"remote\"] = True\n    return TemplateResponse(request, \"search/book.html\", data)\n\n\ndef user_search(request):\n    \"\"\"cool kids members only user search\"\"\"\n    viewer = request.user\n    query = request.GET.get(\"q\")\n    query = query.strip()\n    data = {\"type\": \"user\", \"query\": query}\n    # logged out viewers can't search users\n    if not viewer.is_authenticated:\n        return TemplateResponse(request, \"search/user.html\", data)\n\n    # use webfinger for mastodon style account@domain.com username to load the user if\n    # they don't exist locally (handle_remote_webfinger will check the db)\n    if re.match(regex.FULL_USERNAME, query):\n        handle_remote_webfinger(query)\n\n    results = (\n        models.User.viewer_aware_objects(viewer)\n        .annotate(\n            similarity=Greatest(\n                TrigramSimilarity(\"username\", query),\n                TrigramSimilarity(\"localname\", query),\n            )\n        )\n        .filter(\n            similarity__gt=0.5,\n        )\n        .order_by(\"-similarity\")\n    )\n    paginated = Paginator(results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data[\"results\"] = page\n    data[\"page_range\"] = paginated.get_elided_page_range(\n        page.number, on_each_side=2, on_ends=1\n    )\n    return TemplateResponse(request, \"search/user.html\", data)\n\n\ndef list_search(request):\n    \"\"\"any relevent lists?\"\"\"\n    query = request.GET.get(\"q\")\n    data = {\"query\": query, \"type\": \"list\"}\n    results = (\n        models.List.privacy_filter(\n            request.user,\n            privacy_levels=[\"public\", \"followers\"],\n        )\n        .annotate(\n            similarity=Greatest(\n                TrigramSimilarity(\"name\", query),\n                TrigramSimilarity(\"description\", query),\n            )\n        )\n        .filter(\n            similarity__gt=0.1,\n        )\n        .order_by(\"-similarity\")\n    )\n    paginated = Paginator(results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data[\"results\"] = page\n    data[\"page_range\"] = paginated.get_elided_page_range(\n        page.number, on_each_side=2, on_ends=1\n    )\n    return TemplateResponse(request, \"search/list.html\", data)\n\n\ndef isbn_check(query):\n    \"\"\"isbn10 or isbn13 check, if so remove separators\"\"\"\n    if query:\n        su_num = re.sub(r\"(?<=\\d)\\D(?=\\d|[xX])\", \"\", query)\n        if len(su_num) == 13 and su_num.isdecimal():\n            # Multiply every other digit by  3\n            # Add these numbers and the other digits\n            product = sum(int(ch) for ch in su_num[::2]) + sum(\n                int(ch) * 3 for ch in su_num[1::2]\n            )\n            if product % 10 == 0:\n                return su_num\n        elif (\n            len(su_num) == 10\n            and su_num[:-1].isdecimal()\n            and (su_num[-1].isdecimal() or su_num[-1].lower() == \"x\")\n        ):\n            product = 0\n            # Iterate through code_string\n            for i in range(9):\n                # for each character, multiply by a different decreasing number: 10 - x\n                product = product + int(su_num[i]) * (10 - i)\n            # Handle last character\n            if su_num[9].lower() == \"x\":\n                product += 10\n            else:\n                product += int(su_num[9])\n            if product % 11 == 0:\n                return su_num\n    return query\n", "path": "bookwyrm/views/search.py"}], "after_files": [{"content": "\"\"\" search views\"\"\"\nimport re\n\nfrom django.contrib.postgres.search import TrigramSimilarity\nfrom django.core.paginator import Paginator\nfrom django.db.models.functions import Greatest\nfrom django.http import JsonResponse\nfrom django.template.response import TemplateResponse\nfrom django.views import View\n\nfrom csp.decorators import csp_update\n\nfrom bookwyrm import models\nfrom bookwyrm.connectors import connector_manager\nfrom bookwyrm.book_search import search, format_search_result\nfrom bookwyrm.settings import PAGE_LENGTH\nfrom bookwyrm.utils import regex\nfrom .helpers import is_api_request\nfrom .helpers import handle_remote_webfinger\n\n\n# pylint: disable= no-self-use\nclass Search(View):\n    \"\"\"search users or books\"\"\"\n\n    @csp_update(IMG_SRC=\"*\")\n    def get(self, request):\n        \"\"\"that search bar up top\"\"\"\n        if is_api_request(request):\n            return api_book_search(request)\n\n        query = request.GET.get(\"q\")\n        if not query:\n            return TemplateResponse(request, \"search/book.html\")\n\n        search_type = request.GET.get(\"type\")\n        if query and not search_type:\n            search_type = \"user\" if \"@\" in query else \"book\"\n\n        endpoints = {\n            \"book\": book_search,\n            \"user\": user_search,\n            \"list\": list_search,\n        }\n        if not search_type in endpoints:\n            search_type = \"book\"\n\n        return endpoints[search_type](request)\n\n\ndef api_book_search(request):\n    \"\"\"Return books via API response\"\"\"\n    query = request.GET.get(\"q\")\n    query = isbn_check(query)\n    min_confidence = request.GET.get(\"min_confidence\", 0)\n    # only return local book results via json so we don't cascade\n    book_results = search(query, min_confidence=min_confidence)\n    return JsonResponse(\n        [format_search_result(r) for r in book_results[:10]], safe=False\n    )\n\n\ndef book_search(request):\n    \"\"\"the real business is elsewhere\"\"\"\n    query = request.GET.get(\"q\")\n    # check if query is isbn\n    query = isbn_check(query)\n    min_confidence = request.GET.get(\"min_confidence\", 0)\n    search_remote = request.GET.get(\"remote\", False) and request.user.is_authenticated\n\n    # try a local-only search\n    local_results = search(query, min_confidence=min_confidence)\n    paginated = Paginator(local_results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data = {\n        \"query\": query,\n        \"results\": page,\n        \"type\": \"book\",\n        \"remote\": search_remote,\n        \"page_range\": paginated.get_elided_page_range(\n            page.number, on_each_side=2, on_ends=1\n        ),\n    }\n    # if a logged in user requested remote results or got no local results, try remote\n    if request.user.is_authenticated and (not local_results or search_remote):\n        data[\"remote_results\"] = connector_manager.search(\n            query, min_confidence=min_confidence\n        )\n        data[\"remote\"] = True\n    return TemplateResponse(request, \"search/book.html\", data)\n\n\ndef user_search(request):\n    \"\"\"user search: search for a user\"\"\"\n    viewer = request.user\n    query = request.GET.get(\"q\")\n    query = query.strip()\n    data = {\"type\": \"user\", \"query\": query}\n\n    # use webfinger for mastodon style account@domain.com username to load the user if\n    # they don't exist locally (handle_remote_webfinger will check the db)\n    if re.match(regex.FULL_USERNAME, query) and viewer.is_authenticated:\n        handle_remote_webfinger(query)\n\n    results = (\n        models.User.viewer_aware_objects(viewer)\n        .annotate(\n            similarity=Greatest(\n                TrigramSimilarity(\"username\", query),\n                TrigramSimilarity(\"localname\", query),\n            )\n        )\n        .filter(\n            similarity__gt=0.5,\n        )\n        .order_by(\"-similarity\")\n    )\n\n    # don't expose remote users\n    if not viewer.is_authenticated:\n        results = results.filter(local=True)\n\n    paginated = Paginator(results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data[\"results\"] = page\n    data[\"page_range\"] = paginated.get_elided_page_range(\n        page.number, on_each_side=2, on_ends=1\n    )\n    return TemplateResponse(request, \"search/user.html\", data)\n\n\ndef list_search(request):\n    \"\"\"any relevent lists?\"\"\"\n    query = request.GET.get(\"q\")\n    data = {\"query\": query, \"type\": \"list\"}\n    results = (\n        models.List.privacy_filter(\n            request.user,\n            privacy_levels=[\"public\", \"followers\"],\n        )\n        .annotate(\n            similarity=Greatest(\n                TrigramSimilarity(\"name\", query),\n                TrigramSimilarity(\"description\", query),\n            )\n        )\n        .filter(\n            similarity__gt=0.1,\n        )\n        .order_by(\"-similarity\")\n    )\n    paginated = Paginator(results, PAGE_LENGTH)\n    page = paginated.get_page(request.GET.get(\"page\"))\n    data[\"results\"] = page\n    data[\"page_range\"] = paginated.get_elided_page_range(\n        page.number, on_each_side=2, on_ends=1\n    )\n    return TemplateResponse(request, \"search/list.html\", data)\n\n\ndef isbn_check(query):\n    \"\"\"isbn10 or isbn13 check, if so remove separators\"\"\"\n    if query:\n        su_num = re.sub(r\"(?<=\\d)\\D(?=\\d|[xX])\", \"\", query)\n        if len(su_num) == 13 and su_num.isdecimal():\n            # Multiply every other digit by  3\n            # Add these numbers and the other digits\n            product = sum(int(ch) for ch in su_num[::2]) + sum(\n                int(ch) * 3 for ch in su_num[1::2]\n            )\n            if product % 10 == 0:\n                return su_num\n        elif (\n            len(su_num) == 10\n            and su_num[:-1].isdecimal()\n            and (su_num[-1].isdecimal() or su_num[-1].lower() == \"x\")\n        ):\n            product = 0\n            # Iterate through code_string\n            for i in range(9):\n                # for each character, multiply by a different decreasing number: 10 - x\n                product = product + int(su_num[i]) * (10 - i)\n            # Handle last character\n            if su_num[9].lower() == \"x\":\n                product += 10\n            else:\n                product += int(su_num[9])\n            if product % 11 == 0:\n                return su_num\n    return query\n", "path": "bookwyrm/views/search.py"}]}