diff --git a/bookwyrm/migrations/0053_auto_20201014_1700.py b/bookwyrm/migrations/0053_auto_20201014_1700.py
new file mode 100644
index 00000000..d1306dfe
--- /dev/null
+++ b/bookwyrm/migrations/0053_auto_20201014_1700.py
@@ -0,0 +1,15 @@
+# Generated by Django 3.0.7 on 2020-10-14 17:00
+
+from django.contrib.postgres.operations import TrigramExtension
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('bookwyrm', '0052_auto_20201005_2145'),
+ ]
+
+ operations = [
+ TrigramExtension()
+ ]
diff --git a/bookwyrm/outgoing.py b/bookwyrm/outgoing.py
index 25a61c46..0efa8a4a 100644
--- a/bookwyrm/outgoing.py
+++ b/bookwyrm/outgoing.py
@@ -34,7 +34,7 @@ def outbox(request, username):
)
-def handle_account_search(query):
+def handle_remote_webfinger(query):
''' webfingerin' other servers '''
user = None
domain = query.split('@')[1]
@@ -61,14 +61,10 @@ def handle_account_search(query):
def handle_follow(user, to_follow):
''' someone local wants to follow someone '''
- try:
- relationship, _ = models.UserFollowRequest.objects.get_or_create(
- user_subject=user,
- user_object=to_follow,
- )
- except IntegrityError as err:
- if err.__cause__.diag.constraint_name != 'userfollowrequest_unique':
- raise
+ relationship, _ = models.UserFollowRequest.objects.get_or_create(
+ user_subject=user,
+ user_object=to_follow,
+ )
activity = relationship.to_activity()
broadcast(user, activity, direct_recipients=[to_follow])
diff --git a/bookwyrm/templates/search_results.html b/bookwyrm/templates/search_results.html
new file mode 100644
index 00000000..bd5096fe
--- /dev/null
+++ b/bookwyrm/templates/search_results.html
@@ -0,0 +1,45 @@
+{% extends 'layout.html' %}
+{% block content %}
+
+
+
Matching Books
+ {% for result_set in book_results %}
+ {% if result_set.results %}
+
+ {% if not result_set.connector.local %}
+
+ {% endif %}
+
+ {% for result in result_set.results %}
+
+
+
+ {% endfor %}
+
+ {% endif %}
+ {% endfor %}
+ {% if not book_results %}
+
No books found for "{{ query }}"
+ {% endif %}
+
+
+
Matching Users
+ {% if not user_results %}
+
No users found for "{{ query }}"
+ {% endif %}
+ {% for result in user_results %}
+
+ {% include 'snippets/avatar.html' with user=result %}
+ {% include 'snippets/username.html' with user=result show_full=True %}
+ {% include 'snippets/follow_button.html' with user=result %}
+
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/bookwyrm/templates/user_results.html b/bookwyrm/templates/user_results.html
index 9ea169e2..accfdc46 100644
--- a/bookwyrm/templates/user_results.html
+++ b/bookwyrm/templates/user_results.html
@@ -6,6 +6,7 @@
No results found for "{{ query }}"
{% endif %}
{% for result in results %}
+ {{ result }}
{% include 'snippets/avatar.html' with user=result %}
{% include 'snippets/username.html' with user=result show_full=True %}
diff --git a/bookwyrm/views.py b/bookwyrm/views.py
index 2bc840c0..9217c4b3 100644
--- a/bookwyrm/views.py
+++ b/bookwyrm/views.py
@@ -2,6 +2,7 @@
import re
from django.contrib.auth.decorators import login_required, permission_required
+from django.contrib.postgres.search import TrigramSimilarity
from django.db.models import Avg, Count, Q
from django.http import HttpResponseBadRequest, HttpResponseNotFound,\
JsonResponse
@@ -147,22 +148,30 @@ def get_activity_feed(user, filter_level, model=models.Status):
def search(request):
''' that search bar up top '''
query = request.GET.get('q')
- if re.match(r'\w+@\w+.\w+', query):
- # if something looks like a username, search with webfinger
- results = outgoing.handle_account_search(query)
- return TemplateResponse(
- request, 'user_results.html', {'results': results, 'query': query}
- )
-
- # or just send the question over to book search
if is_api_request(request):
- # only return local results via json so we don't cause a cascade
- results = books_manager.local_search(query)
- return JsonResponse([r.__dict__ for r in results], safe=False)
+ # only return local book results via json so we don't cause a cascade
+ book_results = books_manager.local_search(query)
+ return JsonResponse([r.__dict__ for r in book_results], safe=False)
- results = books_manager.search(query)
- return TemplateResponse(request, 'book_results.html', {'results': results})
+ # use webfinger looks like a mastodon style account@domain.com username
+ if re.match(r'\w+@\w+.\w+', query):
+ outgoing.handle_remote_webfinger(query)
+
+ # do a local user search
+ user_results = models.User.objects.annotate(
+ similarity=TrigramSimilarity('username', query),
+ ).filter(
+ similarity__gt=0.1,
+ ).order_by('-similarity')[:10]
+
+ book_results = books_manager.search(query)
+ data = {
+ 'book_results': book_results,
+ 'user_results': user_results,
+ 'query': query,
+ }
+ return TemplateResponse(request, 'search_results.html', data)
@login_required