Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lms/djangoapps/course_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class CourseSerializer(serializers.Serializer): # pylint: disable=abstract-meth
start = serializers.DateTimeField()
start_display = serializers.CharField()
start_type = serializers.CharField()
pacing = serializers.CharField()

# 'course_id' is a deprecated field, please use 'id' instead.
course_id = serializers.CharField(source='id', read_only=True)
Expand Down
14 changes: 14 additions & 0 deletions lms/djangoapps/course_api/tests/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
Test data created by CourseSerializer and CourseDetailSerializer
"""

from __future__ import unicode_literals
from datetime import datetime

import ddt
from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from rest_framework.test import APIRequestFactory
Expand All @@ -18,6 +20,7 @@
from .mixins import CourseApiFactoryMixin


@ddt.ddt
class TestCourseSerializer(CourseApiFactoryMixin, ModuleStoreTestCase):
"""
Test CourseSerializer
Expand Down Expand Up @@ -54,6 +57,7 @@ def setUp(self):
'enrollment_end': u'2015-07-15T00:00:00Z',
'blocks_url': u'http://testserver/api/courses/v1/blocks/?course_id=edX%2Ftoy%2F2012_Fall',
'effort': u'6 hours',
'pacing': 'instructor',

# 'course_id' is a deprecated field, please use 'id' instead.
'course_id': u'edX/toy/2012_Fall',
Expand Down Expand Up @@ -101,6 +105,16 @@ def test_empty_start(self):
self.assertEqual(result['start_type'], u'empty')
self.assertIsNone(result['start_display'])

@ddt.unpack
@ddt.data(
(True, 'self'),
(False, 'instructor'),
)
def test_pacing(self, self_paced, expected_pacing):
course = self.create_course(self_paced=self_paced)
result = self._get_result(course)
self.assertEqual(result['pacing'], expected_pacing)


class TestCourseDetailSerializer(TestCourseSerializer): # pylint: disable=test-inherits-tests
"""
Expand Down
4 changes: 3 additions & 1 deletion lms/djangoapps/course_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class CourseDetailView(DeveloperErrorViewMixin, RetrieveAPIView):
* `"string"`: manually set
* `"timestamp"`: generated form `start` timestamp
* `"empty"`: the start date should not be shown
* pacing: Course pacing. Possible values: instructor, self

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a standard terminology for MOOCs?
@catong Did you have any suggestion on naming for this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In documentation we refer to "self-paced" and "instructor-paced" courses, so those values are fine.


Deprecated fields:

Expand Down Expand Up @@ -94,7 +95,8 @@ class CourseDetailView(DeveloperErrorViewMixin, RetrieveAPIView):
"overview: "<p>A verbose description of the course.</p>"
"start": "2015-07-17T12:00:00Z",
"start_display": "July 17, 2015",
"start_type": "timestamp"
"start_type": "timestamp",
"pacing": "instructor"
}
"""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('course_overviews', '0009_readd_facebook_url'),
]

operations = [
migrations.RemoveField(
model_name='courseoverview',
name='facebook_url',
),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the code change associated with this operation. Should it have been committed previously?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears the followup work for #11673 was not completed. @nasthagiri is there a ticket for this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused about this. The original PR did have migration code for it. However, since then, the devOps team made a change to revert it in order to support production deployment to multiple workers, concurrently running different versions of the code. @jibsheet At this point, can we go ahead and re-add the removal of this field in the migration file?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, the original PR had migration code in it to remove that field from the table without previously having removed it from the model, which would have broken production. That RemoveField calls was removed. You can look at 0008 and 0009 for details.

Now that we've removed the model field in a release, it should be safe to remove the column in another release. 👍 from me, provided we've done the usual work when migrating this table to deal with row versions.

migrations.AddField(
model_name='courseoverview',
name='self_paced',
field=models.BooleanField(default=False),
),
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this added to an existing migration file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new migration file. See my comment about #11673.

14 changes: 13 additions & 1 deletion openedx/core/djangoapps/content/course_overviews/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Meta(object):
app_label = 'course_overviews'

# IMPORTANT: Bump this whenever you modify this model and/or add a migration.
VERSION = 3
VERSION = 4

# Cache entry versioning.
version = IntegerField()
Expand Down Expand Up @@ -98,6 +98,7 @@ class Meta(object):
short_description = TextField(null=True)
course_video_url = TextField(null=True)
effort = TextField(null=True)
self_paced = BooleanField(default=False)

@classmethod
def _create_from_course(cls, course):
Expand Down Expand Up @@ -181,6 +182,7 @@ def _create_from_course(cls, course):
short_description=CourseDetails.fetch_about_attribute(course.id, 'short_description'),
effort=CourseDetails.fetch_about_attribute(course.id, 'effort'),
course_video_url=CourseDetails.fetch_video_url(course.id),
self_paced=course.self_paced,
)

@classmethod
Expand Down Expand Up @@ -551,6 +553,16 @@ def image_urls(self):

return self.apply_cdn_to_urls(urls)

@property
def pacing(self):
""" Returns the pacing for the course.

Potential values:
self: Self-paced courses
instructor: Instructor-led courses
"""
return 'self' if self.self_paced else 'instructor'

def apply_cdn_to_urls(self, image_urls):
"""
Given a dict of resolutions -> urls, return a copy with CDN applied.
Expand Down