Commit cf4605e5 by Clinton Blackburn

Updated search API endpoints

The endpoints now only return published objects.

ECOM-5414
parent 2a83c0ee
......@@ -45,7 +45,7 @@ COURSE_RUN_FACET_FIELD_QUERIES = {
COURSE_RUN_SEARCH_FIELDS = (
'text', 'key', 'title', 'short_description', 'full_description', 'start', 'end', 'enrollment_start',
'enrollment_end', 'pacing_type', 'language', 'transcript_languages', 'marketing_url', 'content_type', 'org',
'number', 'seat_types', 'image_url', 'type', 'level_type', 'availability',
'number', 'seat_types', 'image_url', 'type', 'level_type', 'availability', 'published',
)
PROGRAM_FACET_FIELD_OPTIONS = {
......@@ -57,6 +57,7 @@ PROGRAM_FACET_FIELD_OPTIONS = {
BASE_PROGRAM_FIELDS = (
'text', 'uuid', 'title', 'subtitle', 'type', 'marketing_url', 'content_type', 'status', 'card_image_url',
'published',
)
PROGRAM_SEARCH_FIELDS = BASE_PROGRAM_FIELDS + ('authoring_organizations',)
......
......@@ -606,6 +606,7 @@ class CourseRunSearchSerializerTests(TestCase):
'type': course_run.type,
'level_type': course_run.level_type.name,
'availability': course_run.availability,
'published': course_run.status == CourseRun.Status.Published,
}
self.assertDictEqual(serializer.data, expected)
......@@ -648,6 +649,7 @@ class ProgramSearchSerializerTests(TestCase):
'content_type': 'program',
'card_image_url': program.card_image_url,
'status': program.status,
'published': program.status == Program.Status.Active,
}
self.assertDictEqual(serializer.data, expected)
......@@ -668,5 +670,6 @@ class ProgramSearchSerializerTests(TestCase):
'content_type': 'program',
'card_image_url': program.card_image_url,
'status': program.status,
'published': program.status == Program.Status.Active,
}
self.assertDictEqual(serializer.data, expected)
......@@ -7,24 +7,36 @@ from django.core.urlresolvers import reverse
from haystack.query import SearchQuerySet
from rest_framework.test import APITestCase
from course_discovery.apps.api.serializers import CourseRunSearchSerializer
from course_discovery.apps.api.serializers import CourseRunSearchSerializer, ProgramSearchSerializer
from course_discovery.apps.core.tests.factories import UserFactory, USER_PASSWORD
from course_discovery.apps.core.tests.mixins import ElasticsearchTestMixin
from course_discovery.apps.course_metadata.models import CourseRun
from course_discovery.apps.course_metadata.tests.factories import CourseRunFactory
from course_discovery.apps.course_metadata.models import CourseRun, Program
from course_discovery.apps.course_metadata.tests.factories import CourseRunFactory, ProgramFactory
@ddt.ddt
class CourseRunSearchViewSetTests(ElasticsearchTestMixin, APITestCase):
""" Tests for CourseRunSearchViewSet. """
faceted_path = reverse('api:v1:search-course_runs-facets')
list_path = reverse('api:v1:search-course_runs-list')
class SerializationMixin:
def serialize_course_run(self, course_run):
result = SearchQuerySet().models(CourseRun).filter(key=course_run.key)[0]
return CourseRunSearchSerializer(result).data
def serialize_program(self, program):
result = SearchQuerySet().models(Program).filter(uuid=program.uuid)[0]
return ProgramSearchSerializer(result).data
class LoginMixin:
def setUp(self):
super(CourseRunSearchViewSetTests, self).setUp()
super(LoginMixin, self).setUp()
self.user = UserFactory()
self.client.login(username=self.user.username, password=USER_PASSWORD)
@ddt.ddt
class CourseRunSearchViewSetTests(SerializationMixin, LoginMixin, ElasticsearchTestMixin, APITestCase):
""" Tests for CourseRunSearchViewSet. """
faceted_path = reverse('api:v1:search-course_runs-facets')
list_path = reverse('api:v1:search-course_runs-list')
def get_search_response(self, query=None, faceted=False):
qs = ''
......@@ -35,10 +47,6 @@ class CourseRunSearchViewSetTests(ElasticsearchTestMixin, APITestCase):
url = '{path}?{qs}'.format(path=path, qs=qs)
return self.client.get(url)
def serialize_course_run(self, course_run):
result = SearchQuerySet().models(CourseRun).filter(key=course_run.key)[0]
return CourseRunSearchSerializer(result).data
@ddt.data(True, False)
def test_authentication(self, faceted):
""" Verify the endpoint requires authentication. """
......@@ -65,7 +73,7 @@ class CourseRunSearchViewSetTests(ElasticsearchTestMixin, APITestCase):
""" Asserts the search functionality returns results for a generated query. """
# Generate data that should be indexed and returned by the query
course_run = CourseRunFactory(course__title='Software Testing')
course_run = CourseRunFactory(course__title='Software Testing', status=CourseRun.Status.Published)
response = self.get_search_response('software', faceted=faceted)
self.assertEqual(response.status_code, 200)
......@@ -101,10 +109,14 @@ class CourseRunSearchViewSetTests(ElasticsearchTestMixin, APITestCase):
def test_availability_faceting(self):
""" Verify the endpoint returns availability facets with the results. """
now = datetime.datetime.utcnow()
archived = CourseRunFactory(start=now - datetime.timedelta(weeks=2), end=now - datetime.timedelta(weeks=1))
current = CourseRunFactory(start=now - datetime.timedelta(weeks=2), end=now + datetime.timedelta(weeks=1))
starting_soon = CourseRunFactory(start=now + datetime.timedelta(days=10), end=now + datetime.timedelta(days=90))
upcoming = CourseRunFactory(start=now + datetime.timedelta(days=61), end=now + datetime.timedelta(days=90))
archived = CourseRunFactory(start=now - datetime.timedelta(weeks=2), end=now - datetime.timedelta(weeks=1),
status=CourseRun.Status.Published)
current = CourseRunFactory(start=now - datetime.timedelta(weeks=2), end=now + datetime.timedelta(weeks=1),
status=CourseRun.Status.Published)
starting_soon = CourseRunFactory(start=now + datetime.timedelta(days=10), end=now + datetime.timedelta(days=90),
status=CourseRun.Status.Published)
upcoming = CourseRunFactory(start=now + datetime.timedelta(days=61), end=now + datetime.timedelta(days=90),
status=CourseRun.Status.Published)
response = self.get_search_response(faceted=True)
self.assertEqual(response.status_code, 200)
......@@ -148,3 +160,31 @@ class CourseRunSearchViewSetTests(ElasticsearchTestMixin, APITestCase):
},
}
self.assertDictContainsSubset(expected, response_data['queries'])
class AggregateSearchViewSet(SerializationMixin, LoginMixin, ElasticsearchTestMixin, APITestCase):
path = reverse('api:v1:search-all-facets')
def get_search_response(self, query=None):
qs = ''
if query:
qs = urllib.parse.urlencode({'q': query})
url = '{path}?{qs}'.format(path=self.path, qs=qs)
return self.client.get(url)
def test_results_only_include_published_objects(self):
""" Verify the search results only include items with status set to 'Published'. """
# These items should NOT be in the results
CourseRunFactory(status=CourseRun.Status.Unpublished)
ProgramFactory(status=Program.Status.Unpublished)
course_run = CourseRunFactory(status=CourseRun.Status.Published)
program = ProgramFactory(status=Program.Status.Active)
response = self.get_search_response()
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content.decode('utf-8'))
self.assertListEqual(response_data['objects']['results'],
[self.serialize_course_run(course_run), self.serialize_program(program)])
......@@ -328,7 +328,7 @@ class CourseRunViewSet(viewsets.ReadOnlyModelViewSet):
if query and course_run_ids:
course_run_ids = course_run_ids.split(',')
course_runs = CourseRun.search(query).filter(partner=partner.short_code).filter(key__in=course_run_ids).\
course_runs = CourseRun.search(query).filter(partner=partner.short_code).filter(key__in=course_run_ids). \
values_list('key', flat=True)
contains = {course_run_id: course_run_id in course_runs for course_run_id in course_run_ids}
......@@ -477,7 +477,7 @@ class BaseHaystackViewSet(FacetMixin, HaystackViewSet):
"""
return super(BaseHaystackViewSet, self).list(request, *args, **kwargs)
@list_route(methods=["get"], url_path="facets")
@list_route(methods=['get'], url_path='facets')
def facets(self, request):
"""
Returns faceted search results
......@@ -513,6 +513,9 @@ class BaseHaystackViewSet(FacetMixin, HaystackViewSet):
facet_serializer_cls = self.get_facet_serializer_class()
field_queries = getattr(facet_serializer_cls.Meta, 'field_queries', {})
# Ensure we only return published items
queryset = queryset.filter(published=True)
for facet in self.request.query_params.getlist('selected_query_facets'):
query = field_queries.get(facet)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment