Repository: carpentries/amy

Issue:
Changing Notes >> Comments changes how search function works
With the notes, it used to be that doing a general search would also search the "Notes" field.  For example, searching "maneesha" would return when that term appeared in *any* field - person's name, role, email, and notes.

Now that notes are in comments, it no longer returns comments that include "maneesha."   We should make this so that comments are also included in the search.


Discussion:

Resolving patch:
diff --git a/amy/workshops/forms.py b/amy/workshops/forms.py
--- a/amy/workshops/forms.py
+++ b/amy/workshops/forms.py
@@ -332,6 +332,10 @@ class SearchForm(forms.Form):
                                               required=False,
                                               initial=True)
 
+    in_comments = forms.BooleanField(label='in comments',
+                                     required=False,
+                                     initial=True)
+
     helper = BootstrapHelper(
         add_cancel_button=False,
         use_get_method=True,
diff --git a/amy/workshops/views.py b/amy/workshops/views.py
--- a/amy/workshops/views.py
+++ b/amy/workshops/views.py
@@ -41,6 +41,7 @@
 from django.views.generic.edit import (
     ModelFormMixin,
 )
+from django_comments.models import Comment
 from github.GithubException import GithubException
 from reversion.models import Version, Revision
 from reversion_compare.forms import SelectDiffForm
@@ -1532,12 +1533,13 @@ def search(request):
 
     term = ''
     organizations = events = persons = airports = training_requests = None
+    comments = None
 
-    if request.method == 'GET':
+    if request.method == 'GET' and 'term' in request.GET:
         form = SearchForm(request.GET)
         if form.is_valid():
             term = form.cleaned_data['term']
-            tokens = re.split('\s+', term)
+            tokens = re.split(r'\s+', term)
             results = list()
 
             if form.cleaned_data['in_organizations']:
@@ -1597,9 +1599,29 @@ def search(request):
                 )
                 results += list(training_requests)
 
+            if form.cleaned_data['in_comments']:
+                comments = Comment.objects.filter(
+                    Q(comment__icontains=term) |
+                    Q(user_name__icontains=term) |
+                    Q(user_email__icontains=term) |
+                    Q(user__personal__icontains=term) |
+                    Q(user__family__icontains=term) |
+                    Q(user__email__icontains=term) |
+                    Q(user__github__icontains=term)
+                ).prefetch_related('content_object')
+                results += list(comments)
+
             # only 1 record found? Let's move to it immediately
             if len(results) == 1:
-                return redirect(results[0].get_absolute_url())
+                result = results[0]
+                if isinstance(result, Comment):
+                    return redirect(result.content_object.get_absolute_url() +
+                                    "#c{}".format(result.id))
+                else:
+                    return redirect(result.get_absolute_url())
+
+        else:
+            messages.error(request, 'Fix errors below.')
 
     # if empty GET, we'll create a blank form
     else:
@@ -1613,6 +1635,7 @@ def search(request):
         'events': events,
         'persons': persons,
         'airports': airports,
+        'comments': comments,
         'training_requests': training_requests,
     }
     return render(request, 'workshops/search.html', context)


Test patch:
diff --git a/amy/workshops/tests/test_search.py b/amy/workshops/tests/test_search.py
--- a/amy/workshops/tests/test_search.py
+++ b/amy/workshops/tests/test_search.py
@@ -1,4 +1,8 @@
+from datetime import datetime, timezone
+
+from django.contrib.sites.models import Site
 from django.urls import reverse
+from django_comments.models import Comment
 
 from workshops.tests.base import TestBase
 from workshops.models import Organization, Person, TrainingRequest
@@ -14,13 +18,15 @@ def setUp(self):
     def search_for(self, term,
                    in_organizations=False,
                    in_training_requests=False,
-                   in_persons=False):
+                   in_persons=False,
+                   in_comments=False):
         search_page = self.app.get(reverse('search'), user='admin')
         form = search_page.forms['main-form']
         form['term'] = term
         form['in_organizations'] = in_organizations
         form['in_training_requests'] = in_training_requests
         form['in_persons'] = in_persons
+        form['in_comments'] = in_comments
         return form.submit().maybe_follow()
 
     def test_search_for_organization_with_no_matches(self):
@@ -110,6 +116,33 @@ def test_search_for_training_requests(self):
             'Lorem', in_training_requests=True, in_persons=True)
         self.assertEqual(len(response.context['training_requests']), 1)
 
-        # do not search in_persons, otherwise it'd redirect to Harry Potter's profile
+        # do not search in_persons, otherwise it'd redirect to Harry Potter's
+        # profile
         response = self.search_for('Potter', in_training_requests=True)
         self.assertEqual(len(response.context['training_requests']), 0)
+
+    def test_search_for_comments(self):
+        """After switching from `notes` fields to comments, we need to make
+        sure they're searchable."""
+        Comment.objects.create(
+            content_object=self.org_alpha,
+            user=self.hermione,
+            comment="Testing commenting system for Alpha Organization",
+            submit_date=datetime.now(tz=timezone.utc),
+            site=Site.objects.get_current(),
+        )
+
+        # search for "Alpha" in organizations and comments
+        response = self.search_for('Alpha',
+                                   in_organizations=True,
+                                   in_comments=True)
+
+        self.assertEqual(len(response.context['comments']), 1)
+        self.assertEqual(len(response.context['organizations']), 1)
+
+        # search for "Alpha" only in comments + check redirect
+        response = self.search_for('Alpha',
+                                   in_organizations=False,
+                                   in_comments=True)
+        self.assertEqual(response.request.path,
+                         self.org_alpha.get_absolute_url())