Repository: akvo/akvo-rsr

Issue:
Search in EUTF akvo site
Partner team had a training and workshop with EUTF last week and discovered that search terms in EUTF akvo site returned unrelated results.

Search for tombouctou shows up a project of SNV in EUTF akvo page, which is confusing for the partner as they expect to see their own projects only on their akvo site. 

<img width="1070" alt="screen shot 2017-02-06 at 15 56 41" src="https://cloud.githubusercontent.com/assets/21127166/22652066/45bdf606-ec85-11e6-9c05-25d421b329c1.png">

What the partner expects is to see just projects where they are one of the participating partners. 
If the search does not match any of their projects, it should then not return anything. 


Discussion:
Duplicate of https://github.com/akvo/akvo-rsr/issues/1853

Resolving patch:
diff --git a/akvo/rest/views/typeahead.py b/akvo/rest/views/typeahead.py
--- a/akvo/rest/views/typeahead.py
+++ b/akvo/rest/views/typeahead.py
@@ -13,6 +13,7 @@
 
 from akvo.codelists.models import Country, Version
 from akvo.rsr.models import Organisation, Project, ProjectUpdate
+from akvo.rsr.views.project import _project_directory_coll
 
 from django.conf import settings
 
@@ -59,7 +60,39 @@ def typeahead_user_organisations(request):
 
 @api_view(['GET'])
 def typeahead_project(request):
-    projects = Project.objects.all().exclude(title='')
+    """Return the typeaheads for projects.
+
+    Without any query parameters, it returns the info for all the projects in
+    the current context -- changes depending on whether we are on a partner
+    site, or the RSR site.
+
+    If a project query parameter with a project id is passed, the info for all
+    projects associated with partners for the specified project is returned.
+
+    NOTE: The unauthenticated user gets information about all the projects when
+    using this API endpoint.  More permission checking will need to be added,
+    if the amount of data being returned is changed.
+
+    """
+    project_id = request.GET.get('project', None)
+    if project_id is None:
+        project = None
+
+    else:
+        try:
+            project = Project.objects.get(id=project_id)
+        except Project.DoesNotExist:
+            project = None
+
+    if project is None:
+        # Search bar - organization projects, published
+        projects = _project_directory_coll(request)
+
+    else:
+        # Project editor - all projects of partners for this project
+        projects = Project.objects.of_partners(project.partners.distinct()).distinct()
+
+    projects = projects.exclude(title='')
     return Response(
         rejig(projects, TypeaheadProjectSerializer(projects, many=True))
     )


Test patch:
diff --git a/akvo/rsr/tests/rest/test_typeahead.py b/akvo/rsr/tests/rest/test_typeahead.py
new file mode 100644
--- /dev/null
+++ b/akvo/rsr/tests/rest/test_typeahead.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+
+"""
+Akvo RSR is covered by the GNU Affero General Public License.
+
+See more details in the license.txt file located at the root folder of the Akvo RSR module.
+For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
+"""
+
+from django.conf import settings
+from django.test import Client, TestCase
+
+from akvo.rsr.models import Organisation, Partnership, PartnerSite, Project, PublishingStatus
+
+
+class ProjectTypeaheadTest(TestCase):
+
+    def setUp(self):
+        super(ProjectTypeaheadTest, self).setUp()
+        organisation_name = 'Akvo'
+        organisation = Organisation.objects.create(name=organisation_name)
+        PartnerSite.objects.create(
+            organisation=organisation,
+            piwik_id=1,
+            hostname='akvo'
+        )
+
+        for i in range(1, 6):
+            project = Project.objects.create(title='Project - {}'.format(i))
+            if i < 4:
+                publishing_status = project.publishingstatus
+                publishing_status.status = PublishingStatus.STATUS_PUBLISHED
+                publishing_status.save()
+
+            # Add a partnership for a couple of projects
+            if i in {1, 4}:
+                Partnership.objects.create(
+                    organisation=organisation,
+                    project=project,
+                    iati_organisation_role=Partnership.IATI_REPORTING_ORGANISATION
+                )
+
+            if i == 1:
+                self.project = project
+
+    def _create_client(self, host=None):
+        """ Create and return a client with the given host."""
+        if not host:
+            host = settings.RSR_DOMAIN
+        return Client(HTTP_HOST=host)
+
+    def test_searchable_projects_on_rsr_host(self):
+        # Given
+        url = '/rest/v1/typeaheads/projects?format=json'
+        client = self._create_client()
+
+        # When
+        response = client.get(url)
+
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(response.data['results']), 3)
+
+    def test_project_editor_typeaheads_on_rsr_host(self):
+        # Given
+        url = '/rest/v1/typeaheads/projects?format=json&project={}'.format(self.project.id)
+        client = self._create_client()
+
+        # When
+        response = client.get(url)
+
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(response.data['results']), 2)
+
+    def test_searchable_projects_on_partner_site(self):
+        # Given
+        url = '/rest/v1/typeaheads/projects?format=json'
+        host = 'akvo.{}'.format(settings.AKVOAPP_DOMAIN)
+        client = self._create_client(host)
+
+        # When
+        response = client.get(url)
+
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(response.data['results']), 1)
+
+    def test_all_projects_on_partner_site(self):
+        # Given
+        url = '/rest/v1/typeaheads/projects?format=json&project={}'.format(self.project.id)
+        host = 'akvo.{}'.format(settings.AKVOAPP_DOMAIN)
+        client = self._create_client(host)
+
+        # When
+        response = client.get(url)
+
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(response.data['results']), 2)