Commit 1010c360 by Clinton Blackburn Committed by Clinton Blackburn

Added license field to Course Run model, API endpoint, and search index

The license is now ingested from the Course API on LMS and saved to the Course Run model. This value is in turn exposed on this service's course run and search API endpoints.

LEARNER-2791
parent 2b613ef4
......@@ -138,6 +138,7 @@ class CourseRunFilter(FilterSetMixin, filters.FilterSet):
active = filters.BooleanFilter(method='filter_active')
marketable = filters.BooleanFilter(method='filter_marketable')
keys = CharListFilter(name='key', lookup_expr='in')
license = filters.CharFilter(name='license', lookup_expr='iexact')
@property
def qs(self):
......@@ -150,7 +151,7 @@ class CourseRunFilter(FilterSetMixin, filters.FilterSet):
class Meta:
model = CourseRun
fields = ['keys', 'hidden']
fields = ('keys', 'hidden', 'license',)
class ProgramFilter(FilterSetMixin, filters.FilterSet):
......
......@@ -477,9 +477,9 @@ class CourseRunSerializer(MinimalCourseRunSerializer):
class Meta(MinimalCourseRunSerializer.Meta):
fields = MinimalCourseRunSerializer.Meta.fields + (
'course', 'full_description', 'announcement', 'video', 'seats', 'content_language',
'course', 'full_description', 'announcement', 'video', 'seats', 'content_language', 'license',
'transcript_languages', 'instructors', 'staff', 'min_effort', 'max_effort', 'weeks_to_complete', 'modified',
'level_type', 'availability', 'mobile_available', 'hidden', 'reporting_type', 'eligible_for_financial_aid'
'level_type', 'availability', 'mobile_available', 'hidden', 'reporting_type', 'eligible_for_financial_aid',
)
def get_instructors(self, obj): # pylint: disable=unused-argument
......
......@@ -274,6 +274,7 @@ class CourseRunSerializerTests(MinimalCourseRunSerializerTests):
'availability': course_run.availability,
'reporting_type': course_run.reporting_type,
'status': course_run.status,
'license': course_run.license,
})
return expected
......
......@@ -228,6 +228,14 @@ class CourseRunViewSetTests(SerializationMixin, ElasticsearchTestMixin, APITestC
url = reverse('api:v1:course_run-list') + '?active=1'
self.assert_list_results(url, expected)
def test_filter_by_license(self):
CourseRun.objects.all().delete()
course_runs_cc = CourseRunFactory.create_batch(3, course__partner=self.partner, license='cc-by-sa')
CourseRunFactory.create_batch(3, course__partner=self.partner, license='')
url = reverse('api:v1:course_run-list') + '?license=cc-by-sa'
self.assert_list_results(url, course_runs_cc)
def test_list_exclude_utm(self):
""" Verify the endpoint returns marketing URLs without UTM parameters. """
url = reverse('api:v1:course_run-list') + '?exclude_utm=1'
......
......@@ -83,8 +83,10 @@ class CourseRunAdmin(admin.ModelAdmin):
'hidden',
('language', admin.RelatedOnlyFieldListFilter,),
'status',
'license',
)
ordering = ('key',)
raw_id_fields = ('course',)
readonly_fields = ('uuid',)
search_fields = ('uuid', 'key', 'title_override', 'course__title', 'slug',)
save_error = False
......
......@@ -196,6 +196,9 @@ class CoursesApiDataLoader(AbstractDataLoader):
'hidden': body.get('hidden', False),
}
# NOTE: The license field is non-nullable.
defaults['license'] = body.get('license') or ''
# When using a marketing site, only dates (excluding start) should come from the Course API.
if not self.partner.has_marketing_site:
defaults.update({
......
......@@ -40,6 +40,7 @@ COURSES_API_BODIES = [
'pacing': 'self',
'mobile_available': True,
'hidden': False,
'license': '',
},
{
'effort': None,
......@@ -63,6 +64,7 @@ COURSES_API_BODIES = [
'pacing': 'instructor,',
'mobile_available': False,
'hidden': False,
'license': 'all-rights-reserved',
},
{
# Add a second run of KyotoUx+000x (3T2016) to test merging data across
......
......@@ -186,6 +186,7 @@ class CoursesApiDataLoaderTests(ApiClientTestMixin, DataLoaderTestMixin, TestCas
'short_description_override': None,
'video': None,
'hidden': body.get('hidden', False),
'license': body.get('license', ''),
}
if not partner_has_marketing_site:
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-10-06 20:48
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0061_migrate_subjects_data'),
]
operations = [
migrations.AddField(
model_name='courserun',
name='license',
field=models.CharField(blank=True, db_index=True, max_length=255),
),
]
......@@ -450,6 +450,7 @@ class CourseRun(TimeStampedModel):
)
reporting_type = models.CharField(max_length=255, choices=ReportingType.choices, default=ReportingType.mooc)
eligible_for_financial_aid = models.BooleanField(default=True)
license = models.CharField(max_length=255, blank=True, db_index=True)
tags = TaggableManager(
blank=True,
......
......@@ -169,6 +169,7 @@ class CourseRunIndex(BaseCourseIndex, indexes.Indexable):
subject_uuids = indexes.MultiValueField()
has_enrollable_paid_seats = indexes.BooleanField(null=False)
paid_seat_enrollment_end = indexes.DateTimeField(null=True)
license = indexes.MultiValueField(model_attr='license', faceted=True)
def prepare_aggregation_key(self, obj):
# Aggregate CourseRuns by Course key since that is how we plan to dedup CourseRuns on the marketing site.
......
......@@ -116,6 +116,7 @@ class CourseRunFactory(factory.DjangoModelFactory):
slug = FuzzyText()
hidden = False
weeks_to_complete = FuzzyInteger(1)
license = 'all-rights-reserved'
@factory.post_generation
def staff(self, create, extracted, **kwargs):
......
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