Commit 54feb857 by Clinton Blackburn Committed by GitHub

Merge pull request #345 from edx/clintonb/programs-fix

Programs endpoint fixes
parents 83a32240 fbd4e1c5
...@@ -238,7 +238,7 @@ class OrganizationSerializer(TaggitSerializer, MinimalOrganizationSerializer): ...@@ -238,7 +238,7 @@ class OrganizationSerializer(TaggitSerializer, MinimalOrganizationSerializer):
class Meta(MinimalOrganizationSerializer.Meta): class Meta(MinimalOrganizationSerializer.Meta):
model = Organization model = Organization
fields = MinimalOrganizationSerializer.Meta.fields + ( fields = MinimalOrganizationSerializer.Meta.fields + (
'description', 'homepage_url', 'tags', 'logo_image_url', 'marketing_url' 'description', 'homepage_url', 'tags', 'logo_image_url', 'marketing_url',
) )
...@@ -333,6 +333,7 @@ class ContainedCourseRunsSerializer(serializers.Serializer): ...@@ -333,6 +333,7 @@ class ContainedCourseRunsSerializer(serializers.Serializer):
class MinimalCourseSerializer(TimestampModelSerializer): class MinimalCourseSerializer(TimestampModelSerializer):
course_runs = MinimalCourseRunSerializer(many=True)
owners = MinimalOrganizationSerializer(many=True, source='authoring_organizations') owners = MinimalOrganizationSerializer(many=True, source='authoring_organizations')
class Meta: class Meta:
......
from django.test import TestCase from django.test import TestCase
from course_discovery.apps.api.fields import ImageField from course_discovery.apps.api.fields import ImageField, StdImageSerializerField
from course_discovery.apps.api.tests.test_serializers import make_request
from course_discovery.apps.core.tests.helpers import make_image_file
from course_discovery.apps.course_metadata.tests.factories import ProgramFactory
class ImageFieldTests(TestCase): class ImageFieldTests(TestCase):
...@@ -13,3 +16,27 @@ class ImageFieldTests(TestCase): ...@@ -13,3 +16,27 @@ class ImageFieldTests(TestCase):
'width': None 'width': None
} }
self.assertEqual(ImageField().to_representation(value), expected) self.assertEqual(ImageField().to_representation(value), expected)
# pylint: disable=no-member
class StdImageSerializerFieldTests(TestCase):
def test_to_representation(self):
request = make_request()
# TODO Create test-only model to avoid unnecessary dependency on Program model.
program = ProgramFactory(banner_image=make_image_file('test.jpg'))
field = StdImageSerializerField()
field._context = {'request': request} # pylint: disable=protected-access
expected = {
size_key: {
'url': '{}{}'.format(
'http://testserver',
getattr(program.banner_image, size_key).url
),
'width': program.banner_image.field.variations[size_key]['width'],
'height': program.banner_image.field.variations[size_key]['height']
}
for size_key in program.banner_image.field.variations
}
self.assertDictEqual(field.to_representation(program.banner_image), expected)
...@@ -2,7 +2,7 @@ import ddt ...@@ -2,7 +2,7 @@ import ddt
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase, APIRequestFactory from rest_framework.test import APITestCase, APIRequestFactory
from course_discovery.apps.api.serializers import ProgramSerializer, MinimalProgramSerializer from course_discovery.apps.api.serializers import ProgramSerializer
from course_discovery.apps.core.tests.factories import USER_PASSWORD, UserFactory from course_discovery.apps.core.tests.factories import USER_PASSWORD, UserFactory
from course_discovery.apps.course_metadata.choices import ProgramStatus from course_discovery.apps.course_metadata.choices import ProgramStatus
from course_discovery.apps.course_metadata.models import Program from course_discovery.apps.course_metadata.models import Program
...@@ -69,21 +69,21 @@ class ProgramViewSetTests(APITestCase): ...@@ -69,21 +69,21 @@ class ProgramViewSetTests(APITestCase):
self.assertEqual( self.assertEqual(
response.data['results'], response.data['results'],
MinimalProgramSerializer(expected, many=True, context={'request': self.request}).data ProgramSerializer(expected, many=True, context={'request': self.request}).data
) )
def test_list(self): def test_list(self):
""" Verify the endpoint returns a list of all programs. """ """ Verify the endpoint returns a list of all programs. """
expected = ProgramFactory.create_batch(3) expected = ProgramFactory.create_batch(3)
expected.reverse() expected.reverse()
self.assert_list_results(self.list_path, expected, 7) self.assert_list_results(self.list_path, expected, 40)
def test_filter_by_type(self): def test_filter_by_type(self):
""" Verify that the endpoint filters programs to those of a given type. """ """ Verify that the endpoint filters programs to those of a given type. """
program_type_name = 'foo' program_type_name = 'foo'
program = ProgramFactory(type__name=program_type_name) program = ProgramFactory(type__name=program_type_name)
url = self.list_path + '?type=' + program_type_name url = self.list_path + '?type=' + program_type_name
self.assert_list_results(url, [program], 7) self.assert_list_results(url, [program], 18)
url = self.list_path + '?type=bar' url = self.list_path + '?type=bar'
self.assert_list_results(url, [], 4) self.assert_list_results(url, [], 4)
...@@ -98,11 +98,11 @@ class ProgramViewSetTests(APITestCase): ...@@ -98,11 +98,11 @@ class ProgramViewSetTests(APITestCase):
# Create a third program, which should be filtered out. # Create a third program, which should be filtered out.
ProgramFactory() ProgramFactory()
self.assert_list_results(url, expected, 7) self.assert_list_results(url, expected, 29)
@ddt.data( @ddt.data(
(ProgramStatus.Unpublished, False, 4), (ProgramStatus.Unpublished, False, 4),
(ProgramStatus.Active, True, 7), (ProgramStatus.Active, True, 40),
) )
@ddt.unpack @ddt.unpack
def test_filter_by_marketable(self, status, is_marketable, expected_query_count): def test_filter_by_marketable(self, status, is_marketable, expected_query_count):
......
...@@ -395,6 +395,7 @@ class ProgramViewSet(viewsets.ReadOnlyModelViewSet): ...@@ -395,6 +395,7 @@ class ProgramViewSet(viewsets.ReadOnlyModelViewSet):
lookup_value_regex = '[0-9a-f-]+' lookup_value_regex = '[0-9a-f-]+'
queryset = prefetch_related_objects_for_programs(Program.objects.all()) queryset = prefetch_related_objects_for_programs(Program.objects.all())
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
serializer_class = serializers.ProgramSerializer
filter_backends = (DjangoFilterBackend,) filter_backends = (DjangoFilterBackend,)
filter_class = filters.ProgramFilter filter_class = filters.ProgramFilter
...@@ -403,12 +404,6 @@ class ProgramViewSet(viewsets.ReadOnlyModelViewSet): ...@@ -403,12 +404,6 @@ class ProgramViewSet(viewsets.ReadOnlyModelViewSet):
context['published_course_runs_only'] = int(self.request.GET.get('published_course_runs_only', 0)) context['published_course_runs_only'] = int(self.request.GET.get('published_course_runs_only', 0))
return context return context
def get_serializer_class(self):
if self.action == 'list':
return serializers.MinimalProgramSerializer
return serializers.ProgramSerializer
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
""" List all programs. """ List all programs.
--- ---
......
...@@ -239,13 +239,17 @@ class ProgramFactory(factory.django.DjangoModelFactory): ...@@ -239,13 +239,17 @@ class ProgramFactory(factory.django.DjangoModelFactory):
title = factory.Sequence(lambda n: 'test-program-{}'.format(n)) # pylint: disable=unnecessary-lambda title = factory.Sequence(lambda n: 'test-program-{}'.format(n)) # pylint: disable=unnecessary-lambda
uuid = factory.LazyFunction(uuid4) uuid = factory.LazyFunction(uuid4)
subtitle = 'test-subtitle' subtitle = FuzzyText()
type = factory.SubFactory(ProgramTypeFactory) type = factory.SubFactory(ProgramTypeFactory)
status = ProgramStatus.Unpublished status = ProgramStatus.Unpublished
marketing_slug = factory.Sequence(lambda n: 'test-slug-{}'.format(n)) # pylint: disable=unnecessary-lambda marketing_slug = factory.Sequence(lambda n: 'test-slug-{}'.format(n)) # pylint: disable=unnecessary-lambda
banner_image_url = FuzzyText(prefix='https://example.com/program/banner') banner_image_url = FuzzyText(prefix='https://example.com/program/banner')
card_image_url = FuzzyText(prefix='https://example.com/program/card') card_image_url = FuzzyText(prefix='https://example.com/program/card')
partner = factory.SubFactory(PartnerFactory) partner = factory.SubFactory(PartnerFactory)
overview = FuzzyText()
weeks_to_complete = FuzzyInteger(1)
min_hours_effort_per_week = FuzzyInteger(2)
max_hours_effort_per_week = FuzzyInteger(4)
credit_redemption_overview = FuzzyText() credit_redemption_overview = FuzzyText()
@factory.post_generation @factory.post_generation
...@@ -289,11 +293,6 @@ class ProgramFactory(factory.django.DjangoModelFactory): ...@@ -289,11 +293,6 @@ class ProgramFactory(factory.django.DjangoModelFactory):
add_m2m_data(self.individual_endorsements, extracted) add_m2m_data(self.individual_endorsements, extracted)
@factory.post_generation @factory.post_generation
def staff(self, create, extracted, **kwargs):
if create: # pragma: no cover
add_m2m_data(self.staff, extracted)
@factory.post_generation
def job_outlook_items(self, create, extracted, **kwargs): def job_outlook_items(self, create, extracted, **kwargs):
if create: # pragma: no cover if create: # pragma: no cover
add_m2m_data(self.job_outlook_items, extracted) add_m2m_data(self.job_outlook_items, extracted)
......
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