Repository: learningequality/kolibri

Issue:
links in new search UI are broken
### Observed behavior

observed during testing of #3687

Navigating to one of the other search links results in an error:

![broken-link](https://user-images.githubusercontent.com/2367265/40755061-7e6c37ae-6431-11e8-8016-e725c37ce182.gif)


### Expected behavior

All links should work

### User-facing consequences

sadness

### Errors and logs

![image](https://user-images.githubusercontent.com/2367265/40755374-17db98c0-6433-11e8-9802-a3ffe184896d.png)


### Steps to reproduce

search for something with multiple copies and then click one of the modal links




Discussion:
![](http://i0.kym-cdn.com/entries/icons/facebook/000/020/001/krabs.jpg)


Resolving patch:
diff --git a/kolibri/content/api.py b/kolibri/content/api.py
--- a/kolibri/content/api.py
+++ b/kolibri/content/api.py
@@ -424,7 +424,7 @@ def copies(self, request, pk=None):
             return Response(cache.get(cache_key))
 
         copies = []
-        nodes = models.ContentNode.objects.filter(content_id=pk)
+        nodes = models.ContentNode.objects.filter(content_id=pk, available=True)
         for node in nodes:
             copies.append(node.get_ancestors(include_self=True).values('id', 'title'))
 
@@ -437,7 +437,10 @@ def copies_count(self, request, **kwargs):
         Returns the number of node copies for each content id.
         """
         content_ids = self.request.query_params.get('content_ids', []).split(',')
-        counts = models.ContentNode.objects.filter(content_id__in=content_ids).values('content_id').order_by().annotate(count=Count('content_id'))
+        counts = models.ContentNode.objects.filter(content_id__in=content_ids, available=True) \
+                                           .values('content_id') \
+                                           .order_by() \
+                                           .annotate(count=Count('content_id'))
         return Response(counts)
 
     @detail_route(methods=['get'])


Test patch:
diff --git a/kolibri/content/fixtures/content_test.json b/kolibri/content/fixtures/content_test.json
--- a/kolibri/content/fixtures/content_test.json
+++ b/kolibri/content/fixtures/content_test.json
@@ -72,6 +72,28 @@
     "pk": "32a941fb77c2576e8f6b294cde4c3b0c",
     "model": "content.contentnode"
   },
+  {
+    "fields": {
+      "license_owner": "",
+      "parent": "da7ecc42e62553eebc8121242746e88a",
+      "title": "copy",
+      "license_name": "WTFPL",
+      "tags": [],
+      "kind": "video",
+      "content_id": "c6f49ea527824f398f4d5d26faf19396",
+      "tree_id": 1,
+      "rght": 3,
+      "description": "copy",
+      "available": true,
+      "lft": 2,
+      "sort_order": null,
+      "level": 1,
+      "author": "",
+      "channel_id": "6199dde695db4ee4ab392222d5af1e5c"
+    },
+    "pk": "42a941fb77c2576e8f6b294cde4c3b0c",
+    "model": "content.contentnode"
+  },
   {
     "fields": {
       "license_owner": "",
diff --git a/kolibri/content/test/test_content_app.py b/kolibri/content/test/test_content_app.py
--- a/kolibri/content/test/test_content_app.py
+++ b/kolibri/content/test/test_content_app.py
@@ -534,7 +534,7 @@ def assert_progress(node, progress):
         self.client.login(username="learner", password="pass", facility=facility)
 
         # The progress endpoint is used, so should report progress for topics
-        assert_progress(root, 0.3)
+        assert_progress(root, 0.24)
         assert_progress(c1, 0)
         assert_progress(c2, 0.4)
         assert_progress(c2c1, 0.7)
@@ -560,7 +560,7 @@ def get_progress_fraction(node):
         response = self.client.get(self._reverse_channel_url("contentnodeprogress-list"))
 
         # The progress endpoint is used, so should report progress for topics
-        self.assertEqual(get_progress_fraction(root), 0.3)
+        self.assertEqual(get_progress_fraction(root), 0.24)
         self.assertEqual(get_progress_fraction(c1), 0)
         self.assertEqual(get_progress_fraction(c2), 0.4)
         self.assertEqual(get_progress_fraction(c2c1), 0.7)
@@ -587,7 +587,7 @@ def test_parent_query_cache_hit(self):
     def test_filtering_coach_content_anon(self):
         response = self.client.get(self._reverse_channel_url("contentnode-list"), data={"by_role": True})
         # TODO make content_test.json fixture more organized. Here just, hardcoding the correct count
-        self.assertEqual(len(response.data), 6)
+        self.assertEqual(len(response.data), 7)
 
     def test_filtering_coach_content_admin(self):
         self.client.login(username=self.admin.username, password=DUMMY_PASSWORD)
@@ -670,17 +670,25 @@ def test_in_exam_filter_invalid_value(self):
         self.assertEqual(len(response.data), 0)
 
     def test_copies(self):
+        # the pk is actually a content id
         response = self.client.get(reverse('contentnode-copies', kwargs={'pk': 'c6f49ea527824f398f4d5d26faf19396'}))
-        expected_titles = set(['root', 'c1'])
+        expected_titles = set(['root', 'c1', 'copy'])
         response_titles = set()
         for node in response.data[0]:
             response_titles.add(node['title'])
         self.assertSetEqual(expected_titles, response_titles)
 
+    def test_available_copies(self):
+        # the pk is actually a content id
+        response = self.client.get(reverse('contentnode-copies', kwargs={'pk': 'f2332710c2fd483386cdeb5dcbdda81a'}))
+        # no results should be returned for unavailable content node
+        self.assertEqual(len(response.data), 0)
+
     def test_copies_count(self):
         response = self.client.get(reverse('contentnode-copies-count'),
-                                   data={'content_ids': 'f2332710c2fd483386cdeb5dcbdda81f,c6f49ea527824f398f4d5d26faf15555'})
+                                   data={'content_ids': 'f2332710c2fd483386cdeb5dcbdda81f,c6f49ea527824f398f4d5d26faf15555,f2332710c2fd483386cdeb5dcbdda81a'})
         # assert non existent content id does not show up in results
+        # no results should be returned for unavailable content node
         self.assertEqual(len(response.data), 1)
         self.assertEqual(response.data[0]['count'],
                          content.ContentNode.objects.filter(content_id='f2332710c2fd483386cdeb5dcbdda81f').count())
diff --git a/kolibri/plugins/coach/test/test_coach_api.py b/kolibri/plugins/coach/test/test_coach_api.py
--- a/kolibri/plugins/coach/test/test_coach_api.py
+++ b/kolibri/plugins/coach/test/test_coach_api.py
@@ -73,11 +73,12 @@ def assert_progress(node, progress):
         self.client.login(username="admin", password="pass", facility=facility)
         # Topic so None
         assert_progress(root, [
+            [{'log_count_total': 0, 'total_progress': 0.0, 'log_count_complete': 0}],
             [{'log_count_total': 0, 'total_progress': 0.0, 'log_count_complete': 0}],
             [
                 {'kind': 'audio', 'node_count': 1, 'total_progress': 0.5},
                 {'kind': 'document', 'node_count': 1, 'total_progress': 0.0},
-                {'kind': 'exercise', 'node_count': 1, 'total_progress': 0.7}
+                {'kind': 'exercise', 'node_count': 1, 'total_progress': 0.7},
             ]
         ])
         assert_progress(c2, [