Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
ed798bb9
Commit
ed798bb9
authored
Jun 02, 2016
by
Renzo Lucioni
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12599 from edx/renzo/supplement-program-data
Supplement program data with course and enrollment data
parents
9acc82dd
a8150a51
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
234 additions
and
66 deletions
+234
-66
common/djangoapps/terrain/stubs/programs.py
+13
-3
common/test/acceptance/fixtures/programs.py
+10
-28
common/test/acceptance/pages/lms/programs.py
+2
-1
common/test/acceptance/tests/lms/test_programs.py
+45
-16
common/test/acceptance/tests/studio/test_studio_home.py
+20
-7
lms/djangoapps/learner_dashboard/tests/test_programs.py
+12
-6
lms/djangoapps/learner_dashboard/views.py
+6
-5
openedx/core/djangoapps/programs/tests/test_utils.py
+83
-0
openedx/core/djangoapps/programs/utils.py
+43
-0
No files found.
common/djangoapps/terrain/stubs/programs.py
View file @
ed798bb9
"""
Stub implementation of programs service for acceptance tests
"""
import
re
import
urlparse
from
.http
import
StubHttpRequestHandler
,
StubHttpService
...
...
@@ -11,10 +11,13 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
def
do_GET
(
self
):
# pylint: disable=invalid-name, missing-docstring
pattern_handlers
=
{
"/api/v1/programs/$"
:
self
.
get_programs_list
,
r'/api/v1/programs/$'
:
self
.
get_programs_list
,
r'/api/v1/programs/(\d+)/$'
:
self
.
get_program_details
,
}
if
self
.
match_pattern
(
pattern_handlers
):
return
self
.
send_response
(
404
,
content
=
"404 Not Found"
)
def
match_pattern
(
self
,
pattern_handlers
):
...
...
@@ -25,7 +28,7 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
for
pattern
in
pattern_handlers
:
match
=
re
.
match
(
pattern
,
path
)
if
match
:
pattern_handlers
[
pattern
](
*
*
match
.
groupdict
())
pattern_handlers
[
pattern
](
*
match
.
groups
())
return
True
return
None
...
...
@@ -36,6 +39,13 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
programs
=
self
.
server
.
config
.
get
(
'programs'
,
[])
self
.
send_json_response
(
programs
)
def
get_program_details
(
self
,
program_id
):
"""
Stubs a program details endpoint.
"""
program
=
self
.
server
.
config
.
get
(
'programs.{}'
.
format
(
program_id
),
[])
self
.
send_json_response
(
program
)
class
StubProgramsService
(
StubHttpService
):
# pylint: disable=missing-docstring
HANDLER_CLASS
=
StubProgramsServiceHandler
common/test/acceptance/fixtures/programs.py
View file @
ed798bb9
"""
Tools to create programs-related data for use in bok choy tests.
"""
from
collections
import
namedtuple
import
json
import
requests
from
.
import
PROGRAMS_STUB_URL
from
.config
import
ConfigModelFixture
from
openedx.core.djangoapps.programs.tests
import
factories
FakeProgram
=
namedtuple
(
'FakeProgram'
,
[
'name'
,
'status'
,
'org_key'
,
'course_id'
])
class
ProgramsFixture
(
object
):
"""
Interface to set up mock responses from the Programs stub server.
"""
def
install_programs
(
self
,
fake_programs
):
"""
Sets the response data for the programs list endpoint.
At present, `fake_programs` must be a iterable of FakeProgram named tuples.
"""
programs
=
[]
for
program
in
fake_programs
:
run_mode
=
factories
.
RunMode
(
course_key
=
program
.
course_id
)
course_code
=
factories
.
CourseCode
(
run_modes
=
[
run_mode
])
org
=
factories
.
Organization
(
key
=
program
.
org_key
)
program
=
factories
.
Program
(
name
=
program
.
name
,
status
=
program
.
status
,
organizations
=
[
org
],
course_codes
=
[
course_code
]
)
programs
.
append
(
program
)
api_result
=
{
'results'
:
programs
}
def
install_programs
(
self
,
programs
,
is_list
=
True
):
"""Sets the response data for Programs API endpoints."""
if
is_list
:
key
=
'programs'
api_result
=
{
'results'
:
programs
}
else
:
program
=
programs
[
0
]
key
=
'programs.{}'
.
format
(
program
[
'id'
])
api_result
=
program
requests
.
put
(
'{}/set_config'
.
format
(
PROGRAMS_STUB_URL
),
data
=
{
'programs'
:
json
.
dumps
(
api_result
)},
data
=
{
key
:
json
.
dumps
(
api_result
)},
)
...
...
common/test/acceptance/pages/lms/programs.py
View file @
ed798bb9
...
...
@@ -24,7 +24,8 @@ class ProgramListingPage(PageObject):
class
ProgramDetailsPage
(
PageObject
):
"""Program details page."""
url
=
BASE_URL
+
'/dashboard/programs/123/program-name/'
program_id
=
123
url
=
BASE_URL
+
'/dashboard/programs/{}/program-name/'
.
format
(
program_id
)
def
is_browser_on_page
(
self
):
return
self
.
q
(
css
=
'.js-program-details-wrapper'
)
.
present
common/test/acceptance/tests/lms/test_programs.py
View file @
ed798bb9
"""Acceptance tests for LMS-hosted Programs pages"""
from
nose.plugins.attrib
import
attr
from
...fixtures.programs
import
FakeProgram
,
ProgramsFixture
,
ProgramsConfigMixin
from
...fixtures.programs
import
ProgramsFixture
,
ProgramsConfigMixin
from
...fixtures.course
import
CourseFixture
from
..helpers
import
UniqueCourseTest
from
...pages.lms.auto_auth
import
AutoAuthPage
from
...pages.lms.programs
import
ProgramListingPage
,
ProgramDetailsPage
from
openedx.core.djangoapps.programs.tests
import
factories
class
ProgramPageBase
(
ProgramsConfigMixin
,
UniqueCourseTest
):
...
...
@@ -15,16 +16,33 @@ class ProgramPageBase(ProgramsConfigMixin, UniqueCourseTest):
self
.
set_programs_api_configuration
(
is_enabled
=
True
)
def
stub_api
(
self
,
course_id
=
None
):
"""Stub out the programs API with fake data."""
name
=
'Fake Program'
status
=
'active'
org_key
=
self
.
course_info
[
'org'
]
def
create_program
(
self
,
program_id
=
None
,
course_id
=
None
):
"""DRY helper for creating test program data."""
course_id
=
course_id
if
course_id
else
self
.
course_id
ProgramsFixture
()
.
install_programs
([
FakeProgram
(
name
=
name
,
status
=
status
,
org_key
=
org_key
,
course_id
=
course_id
),
])
run_mode
=
factories
.
RunMode
(
course_key
=
course_id
)
course_code
=
factories
.
CourseCode
(
run_modes
=
[
run_mode
])
org
=
factories
.
Organization
(
key
=
self
.
course_info
[
'org'
])
if
program_id
:
program
=
factories
.
Program
(
id
=
program_id
,
status
=
'active'
,
organizations
=
[
org
],
course_codes
=
[
course_code
]
)
else
:
program
=
factories
.
Program
(
status
=
'active'
,
organizations
=
[
org
],
course_codes
=
[
course_code
]
)
return
program
def
stub_api
(
self
,
programs
,
is_list
=
True
):
"""Stub out the programs API with fake data."""
ProgramsFixture
()
.
install_programs
(
programs
,
is_list
=
is_list
)
def
auth
(
self
,
enroll
=
True
):
"""Authenticate, enrolling the user in the configured course if requested."""
...
...
@@ -43,8 +61,10 @@ class ProgramListingPageTest(ProgramPageBase):
def
test_no_enrollments
(
self
):
"""Verify that no cards appear when the user has no enrollments."""
self
.
stub_api
()
program
=
self
.
create_program
()
self
.
stub_api
([
program
])
self
.
auth
(
enroll
=
False
)
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
...
...
@@ -59,8 +79,11 @@ class ProgramListingPageTest(ProgramPageBase):
self
.
course_info
[
'run'
],
'other_run'
)
self
.
stub_api
(
course_id
=
course_id
)
program
=
self
.
create_program
(
course_id
=
course_id
)
self
.
stub_api
([
program
])
self
.
auth
()
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
...
...
@@ -71,8 +94,10 @@ class ProgramListingPageTest(ProgramPageBase):
Verify that cards appear when the user has enrollments
which are included in at least one active program.
"""
self
.
stub_api
()
program
=
self
.
create_program
()
self
.
stub_api
([
program
])
self
.
auth
()
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
...
...
@@ -87,9 +112,11 @@ class ProgramListingPageA11yTest(ProgramPageBase):
self
.
listing_page
=
ProgramListingPage
(
self
.
browser
)
program
=
self
.
create_program
()
self
.
stub_api
([
program
])
def
test_empty_a11y
(
self
):
"""Test a11y of the page's empty state."""
self
.
stub_api
()
self
.
auth
(
enroll
=
False
)
self
.
listing_page
.
visit
()
...
...
@@ -100,7 +127,6 @@ class ProgramListingPageA11yTest(ProgramPageBase):
def
test_cards_a11y
(
self
):
"""Test a11y when program cards are present."""
self
.
stub_api
()
self
.
auth
()
self
.
listing_page
.
visit
()
...
...
@@ -118,9 +144,12 @@ class ProgramDetailsPageA11yTest(ProgramPageBase):
self
.
details_page
=
ProgramDetailsPage
(
self
.
browser
)
program
=
self
.
create_program
(
program_id
=
self
.
details_page
.
program_id
)
self
.
stub_api
([
program
],
is_list
=
False
)
def
test_a11y
(
self
):
"""Test
a11y of the page's stat
e."""
self
.
auth
(
enroll
=
False
)
"""Test
the page's a11y complianc
e."""
self
.
auth
()
self
.
details_page
.
visit
()
self
.
details_page
.
a11y_audit
.
check_for_accessibility_errors
()
common/test/acceptance/tests/studio/test_studio_home.py
View file @
ed798bb9
...
...
@@ -8,7 +8,7 @@ from uuid import uuid4
from
...fixtures
import
PROGRAMS_STUB_URL
from
...fixtures.config
import
ConfigModelFixture
from
...fixtures.programs
import
FakeProgram
,
ProgramsFixture
,
ProgramsConfigMixin
from
...fixtures.programs
import
ProgramsFixture
,
ProgramsConfigMixin
from
...pages.studio.auto_auth
import
AutoAuthPage
from
...pages.studio.library
import
LibraryEditPage
from
...pages.studio.index
import
DashboardPage
,
DashboardPageWithPrograms
...
...
@@ -17,6 +17,7 @@ from ..helpers import (
select_option_by_text
,
get_selected_option_text
)
from
openedx.core.djangoapps.programs.tests
import
factories
class
CreateLibraryTest
(
WebAppTest
):
...
...
@@ -111,11 +112,24 @@ class DashboardProgramsTabTest(ProgramsConfigMixin, WebAppTest):
via config, and the results of the program list should display when
the list is nonempty.
"""
test_program_values
=
[
FakeProgram
(
name
=
'first program'
,
status
=
'unpublished'
,
org_key
=
'org1'
,
course_id
=
'foo/bar/baz'
),
FakeProgram
(
name
=
'second program'
,
status
=
'unpublished'
,
org_key
=
'org2'
,
course_id
=
'qux/quux/corge'
),
test_program_values
=
[(
'first program'
,
'org1'
),
(
'second program'
,
'org2'
)]
programs
=
[
factories
.
Program
(
name
=
name
,
organizations
=
[
factories
.
Organization
(
key
=
org
),
],
course_codes
=
[
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(),
]),
]
)
for
name
,
org
in
test_program_values
]
ProgramsFixture
()
.
install_programs
(
test_program_values
)
ProgramsFixture
()
.
install_programs
(
programs
)
self
.
set_programs_api_configuration
(
True
)
...
...
@@ -126,8 +140,7 @@ class DashboardProgramsTabTest(ProgramsConfigMixin, WebAppTest):
self
.
assertFalse
(
self
.
dashboard_page
.
is_empty_list_create_button_present
())
results
=
self
.
dashboard_page
.
get_program_list
()
expected
=
[(
p
.
name
,
p
.
org_key
)
for
p
in
test_program_values
]
self
.
assertEqual
(
results
,
expected
)
self
.
assertEqual
(
results
,
test_program_values
)
def
test_tab_requires_staff
(
self
):
"""
...
...
lms/djangoapps/learner_dashboard/tests/test_programs.py
View file @
ed798bb9
...
...
@@ -24,7 +24,7 @@ from openedx.core.djangoapps.programs.tests.mixins import (
ProgramsDataMixin
)
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
,
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
...
...
@@ -231,13 +231,18 @@ class TestProgramListing(
@httpretty.activate
@override_settings
(
MKTG_URLS
=
{
'ROOT'
:
'http://edx.org'
})
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
TestProgramDetails
(
ProgramsApiConfigMixin
,
TestCase
):
class
TestProgramDetails
(
ProgramsApiConfigMixin
,
SharedModuleStore
TestCase
):
"""
Unit tests for the program details page
"""
program_id
=
123
password
=
'test'
@classmethod
def
setUpClass
(
cls
):
super
(
TestProgramDetails
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
()
def
setUp
(
self
):
super
(
TestProgramDetails
,
self
)
.
setUp
()
...
...
@@ -248,11 +253,12 @@ class TestProgramDetails(ProgramsApiConfigMixin, TestCase):
ClientFactory
(
name
=
ProgramsApiConfig
.
OAUTH2_CLIENT_NAME
,
client_type
=
CONFIDENTIAL
)
self
.
organization
=
factories
.
Organization
()
self
.
run_mode
=
factories
.
RunMode
(
course_key
=
unicode
(
self
.
course
.
id
))
# pylint: disable=no-member
self
.
course_code
=
factories
.
CourseCode
(
run_modes
=
[
self
.
run_mode
])
self
.
data
=
factories
.
Program
(
organizations
=
[
factories
.
Organization
()],
course_codes
=
[
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
()]),
]
organizations
=
[
self
.
organization
],
course_codes
=
[
self
.
course_code
]
)
def
_mock_programs_api
(
self
):
...
...
lms/djangoapps/learner_dashboard/views.py
View file @
ed798bb9
...
...
@@ -3,13 +3,13 @@ from urlparse import urljoin
from
django.conf
import
settings
from
django.contrib.auth.decorators
import
login_required
from
django.views.decorators.http
import
require_GET
from
django.http
import
Http404
from
django.views.decorators.http
import
require_GET
from
edxmako.shortcuts
import
render_to_response
from
openedx.core.djangoapps.credentials.utils
import
get_programs_credentials
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
from
openedx.core.djangoapps.programs
.utils
import
ProgramProgressMeter
,
get_programs
,
get_display_category
from
openedx.core.djangoapps.programs
import
utils
from
student.views
import
get_course_enrollments
...
...
@@ -22,13 +22,13 @@ def view_programs(request):
raise
Http404
enrollments
=
list
(
get_course_enrollments
(
request
.
user
,
None
,
[]))
meter
=
ProgramProgressMeter
(
request
.
user
,
enrollments
)
meter
=
utils
.
ProgramProgressMeter
(
request
.
user
,
enrollments
)
programs
=
meter
.
engaged_programs
# TODO: Pull 'xseries' string from configuration model.
marketing_root
=
urljoin
(
settings
.
MKTG_URLS
.
get
(
'ROOT'
),
'xseries'
)
.
strip
(
'/'
)
for
program
in
programs
:
program
[
'display_category'
]
=
get_display_category
(
program
)
program
[
'display_category'
]
=
utils
.
get_display_category
(
program
)
program
[
'marketing_url'
]
=
'{root}/{slug}'
.
format
(
root
=
marketing_root
,
slug
=
program
[
'marketing_slug'
]
...
...
@@ -56,7 +56,8 @@ def program_details(request, program_id):
if
not
show_program_details
:
raise
Http404
program_data
=
get_programs
(
request
.
user
,
program_id
=
program_id
)
program_data
=
utils
.
get_programs
(
request
.
user
,
program_id
=
program_id
)
program_data
=
utils
.
supplement_program_data
(
program_data
,
request
.
user
)
context
=
{
'program_data'
:
program_data
,
...
...
openedx/core/djangoapps/programs/tests/test_utils.py
View file @
ed798bb9
"""Tests covering Programs utilities."""
import
copy
import
datetime
import
json
from
unittest
import
skipUnless
import
ddt
from
django.conf
import
settings
from
django.core.cache
import
cache
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django.utils
import
timezone
import
httpretty
import
mock
from
nose.plugins.attrib
import
attr
...
...
@@ -12,6 +17,7 @@ from edx_oauth2_provider.tests.factories import ClientFactory
from
provider.constants
import
CONFIDENTIAL
from
lms.djangoapps.certificates.api
import
MODES
from
openedx.core.djangoapps.content.course_overviews.models
import
CourseOverview
from
openedx.core.djangoapps.credentials.tests
import
factories
as
credentials_factories
from
openedx.core.djangoapps.credentials.tests.mixins
import
CredentialsApiConfigMixin
,
CredentialsDataMixin
from
openedx.core.djangoapps.programs
import
utils
...
...
@@ -20,6 +26,8 @@ from openedx.core.djangoapps.programs.tests import factories
from
openedx.core.djangoapps.programs.tests.mixins
import
ProgramsApiConfigMixin
,
ProgramsDataMixin
from
openedx.core.djangolib.testing.utils
import
CacheIsolationTestCase
from
student.tests.factories
import
UserFactory
,
CourseEnrollmentFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
UTILS_MODULE
=
'openedx.core.djangoapps.programs.utils'
...
...
@@ -597,3 +605,78 @@ class TestProgramProgressMeter(ProgramsApiConfigMixin, TestCase):
meter
,
factories
.
Progress
(
id
=
program
[
'id'
],
completed
=
self
.
_extract_names
(
program
,
0
))
)
@ddt.ddt
@skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
TestSupplementProgramData
(
ProgramsApiConfigMixin
,
ModuleStoreTestCase
):
"""Tests of the utility function used to supplement program data."""
password
=
'test'
human_friendly_format
=
'
%
x'
maxDiff
=
None
def
setUp
(
self
):
super
(
TestSupplementProgramData
,
self
)
.
setUp
()
self
.
user
=
UserFactory
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
self
.
password
)
ClientFactory
(
name
=
ProgramsApiConfig
.
OAUTH2_CLIENT_NAME
,
client_type
=
CONFIDENTIAL
)
self
.
course
=
CourseFactory
()
self
.
course
.
start
=
timezone
.
now
()
-
datetime
.
timedelta
(
days
=
1
)
self
.
course
.
end
=
timezone
.
now
()
+
datetime
.
timedelta
(
days
=
1
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
self
.
organization
=
factories
.
Organization
()
self
.
run_mode
=
factories
.
RunMode
(
course_key
=
unicode
(
self
.
course
.
id
))
# pylint: disable=no-member
self
.
course_code
=
factories
.
CourseCode
(
run_modes
=
[
self
.
run_mode
])
self
.
program
=
factories
.
Program
(
organizations
=
[
self
.
organization
],
course_codes
=
[
self
.
course_code
]
)
def
_assert_supplemented
(
self
,
actual
,
is_enrolled
=
False
,
is_enrollment_open
=
True
):
"""DRY helper used to verify that program data is extended correctly."""
course_overview
=
CourseOverview
.
get_from_id
(
self
.
course
.
id
)
# pylint: disable=no-member
run_mode
=
factories
.
RunMode
(
course_key
=
unicode
(
self
.
course
.
id
),
# pylint: disable=no-member
course_url
=
reverse
(
'course_root'
,
args
=
[
self
.
course
.
id
]),
# pylint: disable=no-member
course_image_url
=
course_overview
.
course_image_url
,
start_date
=
self
.
course
.
start
.
strftime
(
self
.
human_friendly_format
),
end_date
=
self
.
course
.
end
.
strftime
(
self
.
human_friendly_format
),
is_enrolled
=
is_enrolled
,
is_enrollment_open
=
is_enrollment_open
,
marketing_url
=
''
,
)
course_code
=
factories
.
CourseCode
(
display_name
=
self
.
course_code
[
'display_name'
],
run_modes
=
[
run_mode
])
expected
=
copy
.
deepcopy
(
self
.
program
)
expected
[
'course_codes'
]
=
[
course_code
]
self
.
assertEqual
(
actual
,
expected
)
@ddt.data
(
True
,
False
)
def
test_student_enrollment_status
(
self
,
is_enrolled
):
"""Verify that program data is supplemented correctly."""
if
is_enrolled
:
CourseEnrollmentFactory
(
user
=
self
.
user
,
course_id
=
self
.
course
.
id
)
# pylint: disable=no-member
data
=
utils
.
supplement_program_data
(
self
.
program
,
self
.
user
)
self
.
_assert_supplemented
(
data
,
is_enrolled
=
is_enrolled
)
@ddt.data
(
[
1
,
1
,
False
],
[
1
,
-
1
,
True
],
)
@ddt.unpack
def
test_course_enrollment_status
(
self
,
start_offset
,
end_offset
,
is_enrollment_open
):
"""Verify that course enrollment status is reflected correctly."""
self
.
course
.
enrollment_start
=
timezone
.
now
()
-
datetime
.
timedelta
(
days
=
start_offset
)
self
.
course
.
enrollment_end
=
timezone
.
now
()
-
datetime
.
timedelta
(
days
=
end_offset
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
data
=
utils
.
supplement_program_data
(
self
.
program
,
self
.
user
)
self
.
_assert_supplemented
(
data
,
is_enrollment_open
=
is_enrollment_open
)
openedx/core/djangoapps/programs/utils.py
View file @
ed798bb9
# -*- coding: utf-8 -*-
"""Helper functions for working with Programs."""
import
datetime
import
logging
from
django.core.urlresolvers
import
reverse
from
django.utils
import
timezone
from
opaque_keys.edx.keys
import
CourseKey
import
pytz
from
lms.djangoapps.certificates.api
import
get_certificates_for_user
,
is_passing_status
from
openedx.core.djangoapps.content.course_overviews.models
import
CourseOverview
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
from
openedx.core.lib.edx_api_utils
import
get_edx_api_data
from
student.models
import
CourseEnrollment
from
xmodule.course_metadata_utils
import
DEFAULT_START_DATE
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -275,3 +284,37 @@ class ProgramProgressMeter(object):
}
return
parsed
def
supplement_program_data
(
program_data
,
user
):
"""Supplement program course codes with CourseOverview and CourseEnrollment data.
Arguments:
program_data (dict): Representation of a program.
user (User): The user whose enrollments to inspect.
"""
for
course_code
in
program_data
[
'course_codes'
]:
for
run_mode
in
course_code
[
'run_modes'
]:
course_key
=
CourseKey
.
from_string
(
run_mode
[
'course_key'
])
course_overview
=
CourseOverview
.
get_from_id
(
course_key
)
run_mode
[
'course_url'
]
=
reverse
(
'course_root'
,
args
=
[
course_key
])
run_mode
[
'course_image_url'
]
=
course_overview
.
course_image_url
human_friendly_format
=
'
%
x'
start_date
=
course_overview
.
start
or
DEFAULT_START_DATE
end_date
=
course_overview
.
end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
pytz
.
UTC
)
run_mode
[
'start_date'
]
=
start_date
.
strftime
(
human_friendly_format
)
run_mode
[
'end_date'
]
=
end_date
.
strftime
(
human_friendly_format
)
run_mode
[
'is_enrolled'
]
=
CourseEnrollment
.
is_enrolled
(
user
,
course_key
)
enrollment_start
=
course_overview
.
enrollment_start
or
datetime
.
datetime
.
min
.
replace
(
tzinfo
=
pytz
.
UTC
)
enrollment_end
=
course_overview
.
enrollment_end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
pytz
.
UTC
)
is_enrollment_open
=
enrollment_start
<=
timezone
.
now
()
<
enrollment_end
run_mode
[
'is_enrollment_open'
]
=
is_enrollment_open
# TODO: Currently unavailable on LMS.
run_mode
[
'marketing_url'
]
=
''
return
program_data
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment