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
1b2fbbd6
Commit
1b2fbbd6
authored
Nov 30, 2016
by
Gregory Martin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
delete datetext functions, implement dateutils
parent
bd87b218
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
143 additions
and
524 deletions
+143
-524
common/lib/xmodule/xmodule/course_metadata_utils.py
+0
-80
common/lib/xmodule/xmodule/course_module.py
+4
-29
common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py
+1
-83
common/lib/xmodule/xmodule/tests/test_course_module.py
+1
-61
lms/djangoapps/ccx/models.py
+0
-31
lms/djangoapps/ccx/tests/test_models.py
+1
-92
lms/djangoapps/learner_dashboard/views.py
+3
-1
lms/djangoapps/shoppingcart/models.py
+9
-10
lms/djangoapps/verify_student/tests/test_views.py
+1
-4
lms/static/js/discovery/discovery_factory.js
+8
-2
lms/static/js/discovery/views/course_card.js
+31
-18
lms/static/js/discovery/views/courses_listing.js
+3
-0
lms/static/js/learner_dashboard/models/course_card_model.js
+37
-8
lms/static/js/learner_dashboard/views/program_details_view.js
+2
-1
lms/static/js/spec/discovery/views/course_card_spec.js
+1
-1
lms/static/js/spec/learner_dashboard/course_card_view_spec.js
+12
-2
lms/static/js/verify_student/pay_and_verify.js
+0
-2
lms/static/js/verify_student/views/enrollment_confirmation_step_view.js
+0
-1
lms/static/js/verify_student/views/payment_confirmation_step_view.js
+0
-1
lms/templates/courseware/courses.html
+3
-1
lms/templates/learner_dashboard/program_details.html
+1
-0
lms/templates/shoppingcart/receipt.html
+0
-20
lms/templates/shoppingcart/registration_code_receipt.html
+0
-6
lms/templates/shoppingcart/registration_code_redemption.html
+0
-5
lms/templates/shoppingcart/shopping_cart.html
+0
-4
lms/templates/verify_student/enrollment_confirmation_step.underscore
+2
-4
lms/templates/verify_student/pay_and_verify.html
+0
-4
openedx/core/djangoapps/content/course_overviews/models.py
+0
-30
openedx/core/djangoapps/content/course_overviews/tests.py
+0
-4
openedx/core/djangoapps/programs/tests/test_utils.py
+12
-10
openedx/core/djangoapps/programs/utils.py
+11
-9
No files found.
common/lib/xmodule/xmodule/course_metadata_utils.py
View file @
1b2fbbd6
...
...
@@ -10,11 +10,8 @@ from datetime import datetime, timedelta
import
dateutil.parser
from
math
import
exp
from
openedx.core.lib.time_zone_utils
import
get_time_zone_abbr
from
pytz
import
utc
from
.fields
import
Date
DEFAULT_START_DATE
=
datetime
(
2030
,
1
,
1
,
tzinfo
=
utc
)
...
...
@@ -96,83 +93,6 @@ def course_start_date_is_default(start, advertised_start):
return
advertised_start
is
None
and
start
==
DEFAULT_START_DATE
def
_datetime_to_string
(
date_time
,
format_string
,
time_zone
,
strftime_localized
):
"""
Formats the given datetime with the given function and format string.
Adds time zone abbreviation to the resulting string if the format is DATE_TIME or TIME.
Arguments:
date_time (datetime): the datetime to be formatted
format_string (str): the date format type, as passed to strftime
time_zone (pytz time zone): the time zone to convert to
strftime_localized ((datetime, str) -> str): a nm localized string
formatting function
"""
result
=
strftime_localized
(
date_time
.
astimezone
(
time_zone
),
format_string
)
abbr
=
get_time_zone_abbr
(
time_zone
,
date_time
)
return
(
result
+
' '
+
abbr
if
format_string
in
[
'DATE_TIME'
,
'TIME'
,
'DAY_AND_TIME'
]
else
result
)
def
course_start_datetime_text
(
start_date
,
advertised_start
,
format_string
,
time_zone
,
ugettext
,
strftime_localized
):
"""
Calculates text to be shown to user regarding a course's start
datetime in specified time zone.
Prefers .advertised_start, then falls back to .start.
Arguments:
start_date (datetime): the course's start datetime
advertised_start (str): the course's advertised start date
format_string (str): the date format type, as passed to strftime
time_zone (pytz time zone): the time zone to convert to
ugettext ((str) -> str): a text localization function
strftime_localized ((datetime, str) -> str): a localized string
formatting function
"""
if
advertised_start
is
not
None
:
# TODO: This will return an empty string if advertised_start == ""... consider changing this behavior?
try
:
# from_json either returns a Date, returns None, or raises a ValueError
parsed_advertised_start
=
Date
()
.
from_json
(
advertised_start
)
if
parsed_advertised_start
is
not
None
:
# In the Django implementation of strftime_localized, if
# the year is <1900, _datetime_to_string will raise a ValueError.
return
_datetime_to_string
(
parsed_advertised_start
,
format_string
,
time_zone
,
strftime_localized
)
except
ValueError
:
pass
return
advertised_start
.
title
()
elif
start_date
!=
DEFAULT_START_DATE
:
return
_datetime_to_string
(
start_date
,
format_string
,
time_zone
,
strftime_localized
)
else
:
_
=
ugettext
# Translators: TBD stands for 'To Be Determined' and is used when a course
# does not yet have an announced start date.
return
_
(
'TBD'
)
def
course_end_datetime_text
(
end_date
,
format_string
,
time_zone
,
strftime_localized
):
"""
Returns a formatted string for a course's end date or datetime.
If end_date is None, an empty string will be returned.
Arguments:
end_date (datetime): the end datetime of a course
format_string (str): the date format type, as passed to strftime
time_zone (pytz time zone): the time zone to convert to
strftime_localized ((datetime, str) -> str): a localized string
formatting function
"""
return
(
_datetime_to_string
(
end_date
,
format_string
,
time_zone
,
strftime_localized
)
if
end_date
is
not
None
else
''
)
def
may_certify_for_course
(
certificates_display_behavior
,
certificates_show_before_end
,
has_ended
):
"""
Returns whether it is acceptable to show the student a certificate download
...
...
common/lib/xmodule/xmodule/course_module.py
View file @
1b2fbbd6
...
...
@@ -197,10 +197,11 @@ class CourseFields(object):
scope
=
Scope
.
settings
,
)
advertised_start
=
String
(
display_name
=
_
(
"Course Advertised Start
Date
"
),
display_name
=
_
(
"Course Advertised Start"
),
help
=
_
(
"Enter the date you want to advertise as the course start date, if this date is different from the set "
"start date. To advertise the set start date, enter null."
"Enter the text that you want to use as the advertised starting time frame for the course, "
"such as
\"
Winter 2018
\"
. If you enter null for this value, the start date that you have set "
"for this course is used."
),
scope
=
Scope
.
settings
)
...
...
@@ -1211,21 +1212,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor, LicenseMixin):
"""Return the course_id for this course"""
return
self
.
location
.
course_key
def
start_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""
Returns the desired text corresponding the course's start date and time in specified time zone, defaulted
to UTC. Prefers .advertised_start, then falls back to .start
"""
i18n
=
self
.
runtime
.
service
(
self
,
"i18n"
)
return
course_metadata_utils
.
course_start_datetime_text
(
self
.
start
,
self
.
advertised_start
,
format_string
,
time_zone
,
i18n
.
ugettext
,
i18n
.
strftime
)
@property
def
start_date_is_still_default
(
self
):
"""
...
...
@@ -1237,17 +1223,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor, LicenseMixin):
self
.
advertised_start
)
def
end_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""
Returns the end date or date_time for the course formatted as a string.
"""
return
course_metadata_utils
.
course_end_datetime_text
(
self
.
end
,
format_string
,
time_zone
,
self
.
runtime
.
service
(
self
,
"i18n"
)
.
strftime
)
def
get_discussion_blackout_datetimes
(
self
):
"""
Get a list of dicts with start and end fields with datetime values from
...
...
common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py
View file @
1b2fbbd6
...
...
@@ -5,7 +5,7 @@ from collections import namedtuple
from
datetime
import
timedelta
,
datetime
from
unittest
import
TestCase
from
pytz
import
timezone
,
utc
from
pytz
import
utc
from
xmodule.block_metadata_utils
import
(
url_name_for_block
,
display_name_with_default
,
...
...
@@ -18,11 +18,8 @@ from xmodule.course_metadata_utils import (
has_course_ended
,
DEFAULT_START_DATE
,
course_start_date_is_default
,
course_start_datetime_text
,
course_end_datetime_text
,
may_certify_for_course
,
)
from
xmodule.fields
import
Date
from
xmodule.modulestore.tests.utils
import
(
MongoModulestoreBuilder
,
VersioningModulestoreBuilder
,
...
...
@@ -112,12 +109,6 @@ class CourseMetadataUtilsTestCase(TestCase):
test_datetime
=
datetime
(
1945
,
2
,
6
,
4
,
20
,
00
,
tzinfo
=
utc
)
advertised_start_parsable
=
"2038-01-19 03:14:07"
advertised_start_bad_date
=
"215-01-01 10:10:10"
advertised_start_unparsable
=
"This coming fall"
time_zone_normal_parsable
=
"2016-03-27 00:59:00"
time_zone_normal_datetime
=
datetime
(
2016
,
3
,
27
,
00
,
59
,
00
,
tzinfo
=
utc
)
time_zone_daylight_parsable
=
"2016-03-27 01:00:00"
time_zone_daylight_datetime
=
datetime
(
2016
,
3
,
27
,
1
,
00
,
00
,
tzinfo
=
utc
)
FunctionTest
=
namedtuple
(
'FunctionTest'
,
'function scenarios'
)
# pylint: disable=invalid-name
TestScenario
=
namedtuple
(
'TestScenario'
,
'arguments expected_return'
)
# pylint: disable=invalid-name
...
...
@@ -169,79 +160,6 @@ class CourseMetadataUtilsTestCase(TestCase):
TestScenario
((
DEFAULT_START_DATE
,
advertised_start_parsable
),
False
),
TestScenario
((
DEFAULT_START_DATE
,
None
),
True
),
]),
FunctionTest
(
course_start_datetime_text
,
[
# Test parsable advertised start date.
# Expect start datetime to be parsed and formatted back into a string.
TestScenario
(
(
DEFAULT_START_DATE
,
advertised_start_parsable
,
'DATE_TIME'
,
utc
,
noop_gettext
,
mock_strftime_localized
),
mock_strftime_localized
(
Date
()
.
from_json
(
advertised_start_parsable
),
'DATE_TIME'
)
+
" UTC"
),
# Test un-parsable advertised start date.
# Expect date parsing to throw a ValueError, and the advertised
# start to be returned in Title Case.
TestScenario
(
(
test_datetime
,
advertised_start_unparsable
,
'DATE_TIME'
,
utc
,
noop_gettext
,
mock_strftime_localized
),
advertised_start_unparsable
.
title
()
),
# Test parsable advertised start date from before January 1, 1900.
# Expect mock_strftime_localized to throw a ValueError, and the
# advertised start to be returned in Title Case.
TestScenario
(
(
test_datetime
,
advertised_start_bad_date
,
'DATE_TIME'
,
utc
,
noop_gettext
,
mock_strftime_localized
),
advertised_start_bad_date
.
title
()
),
# Test without advertised start date, but with a set start datetime.
# Expect formatted datetime to be returned.
TestScenario
(
(
test_datetime
,
None
,
'SHORT_DATE'
,
utc
,
noop_gettext
,
mock_strftime_localized
),
mock_strftime_localized
(
test_datetime
,
'SHORT_DATE'
)
),
# Test without advertised start date and with default start datetime.
# Expect TBD to be returned.
TestScenario
(
(
DEFAULT_START_DATE
,
None
,
'SHORT_DATE'
,
utc
,
noop_gettext
,
mock_strftime_localized
),
'TBD'
),
# Test correctly formatted start datetime is returned during normal daylight hours
TestScenario
(
(
DEFAULT_START_DATE
,
time_zone_normal_parsable
,
'DATE_TIME'
,
timezone
(
'Europe/Paris'
),
noop_gettext
,
mock_strftime_localized
),
"DATE_TIME "
+
"2016-03-27 01:59:00 CET"
),
# Test correctly formatted start datetime is returned during daylight savings hours
TestScenario
(
(
DEFAULT_START_DATE
,
time_zone_daylight_parsable
,
'DATE_TIME'
,
timezone
(
'Europe/Paris'
),
noop_gettext
,
mock_strftime_localized
),
"DATE_TIME "
+
"2016-03-27 03:00:00 CEST"
)
]),
FunctionTest
(
course_end_datetime_text
,
[
# Test with a set end datetime.
# Expect formatted datetime to be returned.
TestScenario
(
(
test_datetime
,
'TIME'
,
utc
,
mock_strftime_localized
),
mock_strftime_localized
(
test_datetime
,
'TIME'
)
+
" UTC"
),
# Test with default end datetime.
# Expect empty string to be returned.
TestScenario
(
(
None
,
'TIME'
,
utc
,
mock_strftime_localized
),
""
),
# Test correctly formatted end datetime is returned during normal daylight hours
TestScenario
(
(
time_zone_normal_datetime
,
'TIME'
,
timezone
(
'Europe/Paris'
),
mock_strftime_localized
),
"TIME "
+
"2016-03-27 01:59:00 CET"
),
# Test correctly formatted end datetime is returned during daylight savings hours
TestScenario
(
(
time_zone_daylight_datetime
,
'TIME'
,
timezone
(
'Europe/Paris'
),
mock_strftime_localized
),
"TIME "
+
"2016-03-27 03:00:00 CEST"
)
]),
FunctionTest
(
may_certify_for_course
,
[
TestScenario
((
'early_with_info'
,
True
,
True
),
True
),
TestScenario
((
'early_no_info'
,
False
,
False
),
True
),
...
...
common/lib/xmodule/xmodule/tests/test_course_module.py
View file @
1b2fbbd6
...
...
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta
import
itertools
from
fs.memoryfs
import
MemoryFS
from
mock
import
Mock
,
patch
from
pytz
import
timezone
,
utc
from
pytz
import
utc
from
xblock.runtime
import
KvsFieldData
,
DictKeyValueStore
import
xmodule.course_module
...
...
@@ -209,36 +209,6 @@ class IsNewCourseTestCase(unittest.TestCase):
(
xmodule
.
course_module
.
CourseFields
.
start
.
default
,
'January 2014'
,
'January 2014'
,
False
,
'January 2014'
),
]
@patch
(
'xmodule.course_metadata_utils.datetime.now'
)
def
test_start_date_text
(
self
,
gmtime_mock
):
gmtime_mock
.
return_value
=
NOW
for
s
in
self
.
start_advertised_settings
:
d
=
get_dummy_course
(
start
=
s
[
0
],
advertised_start
=
s
[
1
])
print
"Checking start=
%
s advertised=
%
s"
%
(
s
[
0
],
s
[
1
])
self
.
assertEqual
(
d
.
start_datetime_text
(),
s
[
2
])
@patch
(
'xmodule.course_metadata_utils.datetime.now'
)
def
test_start_date_time_text
(
self
,
gmtime_mock
):
gmtime_mock
.
return_value
=
NOW
for
setting
in
self
.
start_advertised_settings
:
course
=
get_dummy_course
(
start
=
setting
[
0
],
advertised_start
=
setting
[
1
])
print
"Checking start=
%
s advertised=
%
s"
%
(
setting
[
0
],
setting
[
1
])
self
.
assertEqual
(
course
.
start_datetime_text
(
"DATE_TIME"
),
setting
[
4
])
@ddt.data
((
"2015-11-01T08:59"
,
'Nov 01, 2015'
,
u'Nov 01, 2015 at 01:59 PDT'
),
(
"2015-11-01T09:00"
,
'Nov 01, 2015'
,
u'Nov 01, 2015 at 01:00 PST'
))
@ddt.unpack
def
test_start_date_time_zone
(
self
,
course_date
,
expected_short_date
,
expected_date_time
):
"""
Test that start datetime text correctly formats datetimes
for normal daylight hours and daylight savings hours
"""
time_zone
=
timezone
(
'America/Los_Angeles'
)
course
=
get_dummy_course
(
start
=
course_date
,
advertised_start
=
course_date
)
self
.
assertEqual
(
course
.
start_datetime_text
(
time_zone
=
time_zone
),
expected_short_date
)
self
.
assertEqual
(
course
.
start_datetime_text
(
"DATE_TIME"
,
time_zone
),
expected_date_time
)
def
test_start_date_is_default
(
self
):
for
s
in
self
.
start_advertised_settings
:
d
=
get_dummy_course
(
start
=
s
[
0
],
advertised_start
=
s
[
1
])
...
...
@@ -276,36 +246,6 @@ class IsNewCourseTestCase(unittest.TestCase):
descriptor
=
get_dummy_course
(
start
=
'2012-12-31T12:00'
)
assert
descriptor
.
is_newish
is
True
def
test_end_date_text
(
self
):
# No end date set, returns empty string.
d
=
get_dummy_course
(
'2012-12-02T12:00'
)
self
.
assertEqual
(
''
,
d
.
end_datetime_text
())
d
=
get_dummy_course
(
'2012-12-02T12:00'
,
end
=
'2014-9-04T12:00'
)
self
.
assertEqual
(
'Sep 04, 2014'
,
d
.
end_datetime_text
())
def
test_end_date_time_text
(
self
):
# No end date set, returns empty string.
course
=
get_dummy_course
(
'2012-12-02T12:00'
)
self
.
assertEqual
(
''
,
course
.
end_datetime_text
(
"DATE_TIME"
))
course
=
get_dummy_course
(
'2012-12-02T12:00'
,
end
=
'2014-9-04T12:00'
)
self
.
assertEqual
(
'Sep 04, 2014 at 12:00 UTC'
,
course
.
end_datetime_text
(
"DATE_TIME"
))
@ddt.data
((
"2015-11-01T08:59"
,
'Nov 01, 2015'
,
u'Nov 01, 2015 at 01:59 PDT'
),
(
"2015-11-01T09:00"
,
'Nov 01, 2015'
,
u'Nov 01, 2015 at 01:00 PST'
))
@ddt.unpack
def
test_end_date_time_zone
(
self
,
course_date
,
expected_short_date
,
expected_date_time
):
"""
Test that end datetime text correctly formats datetimes
for normal daylight hours and daylight savings hours
"""
time_zone
=
timezone
(
'America/Los_Angeles'
)
course
=
get_dummy_course
(
course_date
,
end
=
course_date
)
self
.
assertEqual
(
course
.
end_datetime_text
(
time_zone
=
time_zone
),
expected_short_date
)
self
.
assertEqual
(
course
.
end_datetime_text
(
"DATE_TIME"
,
time_zone
),
expected_date_time
)
class
DiscussionTopicsTestCase
(
unittest
.
TestCase
):
def
test_default_discussion_topics
(
self
):
...
...
lms/djangoapps/ccx/models.py
View file @
1b2fbbd6
...
...
@@ -12,7 +12,6 @@ from pytz import utc
from
lazy
import
lazy
from
ccx_keys.locator
import
CCXLocator
from
openedx.core.lib.time_zone_utils
import
get_time_zone_abbr
from
openedx.core.djangoapps.xmodule_django.models
import
CourseKeyField
,
LocationKeyField
from
xmodule.error_module
import
ErrorDescriptor
from
xmodule.modulestore.django
import
modulestore
...
...
@@ -84,36 +83,6 @@ class CustomCourseForEdX(models.Model):
return
datetime
.
now
(
utc
)
>
self
.
due
def
start_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""Returns the desired text representation of the CCX start datetime
The returned value is in specified time zone, defaulted to UTC.
"""
i18n
=
self
.
course
.
runtime
.
service
(
self
.
course
,
"i18n"
)
strftime
=
i18n
.
strftime
value
=
strftime
(
self
.
start
.
astimezone
(
time_zone
),
format_string
)
if
format_string
==
'DATE_TIME'
:
value
+=
' '
+
get_time_zone_abbr
(
time_zone
,
self
.
start
)
return
value
def
end_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""Returns the desired text representation of the CCX due datetime
If the due date for the CCX is not set, the value returned is the empty
string.
The returned value is in specified time zone, defaulted to UTC.
"""
if
self
.
due
is
None
:
return
''
i18n
=
self
.
course
.
runtime
.
service
(
self
.
course
,
"i18n"
)
strftime
=
i18n
.
strftime
value
=
strftime
(
self
.
due
.
astimezone
(
time_zone
),
format_string
)
if
format_string
==
'DATE_TIME'
:
value
+=
' '
+
get_time_zone_abbr
(
time_zone
,
self
.
due
)
return
value
@property
def
structure
(
self
):
"""
...
...
lms/djangoapps/ccx/tests/test_models.py
View file @
1b2fbbd6
...
...
@@ -4,14 +4,12 @@ tests for the models
import
ddt
import
json
from
datetime
import
datetime
,
timedelta
from
mock
import
patch
from
nose.plugins.attrib
import
attr
from
pytz
import
timezone
,
utc
from
pytz
import
utc
from
student.roles
import
CourseCcxCoachRole
from
student.tests.factories
import
(
AdminFactory
,
)
from
util.tests.test_date_utils
import
fake_ugettext
from
xmodule.modulestore.tests.django_utils
import
(
ModuleStoreTestCase
,
TEST_DATA_SPLIT_MODULESTORE
...
...
@@ -152,95 +150,6 @@ class TestCCX(ModuleStoreTestCase):
"""verify that a ccx without a due date has not ended"""
self
.
assertFalse
(
self
.
ccx
.
has_ended
())
# pylint: disable=no-member
# ensure that the expected localized format will be found by the i18n
# service
@patch
(
'util.date_utils.ugettext'
,
fake_ugettext
(
translations
=
{
"SHORT_DATE_FORMAT"
:
"
%
b
%
d,
%
Y"
,
}))
def
test_start_datetime_short_date
(
self
):
"""verify that the start date for a ccx formats properly by default"""
start
=
datetime
(
2015
,
1
,
1
,
12
,
0
,
0
,
tzinfo
=
utc
)
expected
=
"Jan 01, 2015"
self
.
set_ccx_override
(
'start'
,
start
)
actual
=
self
.
ccx
.
start_datetime_text
()
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
@patch
(
'util.date_utils.ugettext'
,
fake_ugettext
(
translations
=
{
"DATE_TIME_FORMAT"
:
"
%
b
%
d,
%
Y at
%
H:
%
M"
,
}))
def
test_start_datetime_date_time_format
(
self
):
"""verify that the DATE_TIME format also works as expected"""
start
=
datetime
(
2015
,
1
,
1
,
12
,
0
,
0
,
tzinfo
=
utc
)
expected
=
"Jan 01, 2015 at 12:00 UTC"
self
.
set_ccx_override
(
'start'
,
start
)
actual
=
self
.
ccx
.
start_datetime_text
(
'DATE_TIME'
)
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
@ddt.data
((
datetime
(
2015
,
11
,
1
,
8
,
59
,
00
,
tzinfo
=
utc
),
"Nov 01, 2015"
,
"Nov 01, 2015 at 01:59 PDT"
),
(
datetime
(
2015
,
11
,
1
,
9
,
00
,
00
,
tzinfo
=
utc
),
"Nov 01, 2015"
,
"Nov 01, 2015 at 01:00 PST"
))
@ddt.unpack
def
test_start_date_time_zone
(
self
,
start_date_time
,
expected_short_date
,
expected_date_time
):
"""
verify that start date is correctly converted when time zone specified
during normal daylight hours and daylight savings hours
"""
time_zone
=
timezone
(
'America/Los_Angeles'
)
self
.
set_ccx_override
(
'start'
,
start_date_time
)
actual_short_date
=
self
.
ccx
.
start_datetime_text
(
time_zone
=
time_zone
)
# pylint: disable=no-member
actual_datetime
=
self
.
ccx
.
start_datetime_text
(
'DATE_TIME'
,
time_zone
)
# pylint: disable=no-member
self
.
assertEqual
(
expected_short_date
,
actual_short_date
)
self
.
assertEqual
(
expected_date_time
,
actual_datetime
)
@patch
(
'util.date_utils.ugettext'
,
fake_ugettext
(
translations
=
{
"SHORT_DATE_FORMAT"
:
"
%
b
%
d,
%
Y"
,
}))
def
test_end_datetime_short_date
(
self
):
"""verify that the end date for a ccx formats properly by default"""
end
=
datetime
(
2015
,
1
,
1
,
12
,
0
,
0
,
tzinfo
=
utc
)
expected
=
"Jan 01, 2015"
self
.
set_ccx_override
(
'due'
,
end
)
actual
=
self
.
ccx
.
end_datetime_text
()
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
@patch
(
'util.date_utils.ugettext'
,
fake_ugettext
(
translations
=
{
"DATE_TIME_FORMAT"
:
"
%
b
%
d,
%
Y at
%
H:
%
M"
,
}))
def
test_end_datetime_date_time_format
(
self
):
"""verify that the DATE_TIME format also works as expected"""
end
=
datetime
(
2015
,
1
,
1
,
12
,
0
,
0
,
tzinfo
=
utc
)
expected
=
"Jan 01, 2015 at 12:00 UTC"
self
.
set_ccx_override
(
'due'
,
end
)
actual
=
self
.
ccx
.
end_datetime_text
(
'DATE_TIME'
)
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
@ddt.data
((
datetime
(
2015
,
11
,
1
,
8
,
59
,
00
,
tzinfo
=
utc
),
"Nov 01, 2015"
,
"Nov 01, 2015 at 01:59 PDT"
),
(
datetime
(
2015
,
11
,
1
,
9
,
00
,
00
,
tzinfo
=
utc
),
"Nov 01, 2015"
,
"Nov 01, 2015 at 01:00 PST"
))
@ddt.unpack
def
test_end_datetime_time_zone
(
self
,
end_date_time
,
expected_short_date
,
expected_date_time
):
"""
verify that end date is correctly converted when time zone specified
during normal daylight hours and daylight savings hours
"""
time_zone
=
timezone
(
'America/Los_Angeles'
)
self
.
set_ccx_override
(
'due'
,
end_date_time
)
actual_short_date
=
self
.
ccx
.
end_datetime_text
(
time_zone
=
time_zone
)
# pylint: disable=no-member
actual_datetime
=
self
.
ccx
.
end_datetime_text
(
'DATE_TIME'
,
time_zone
)
# pylint: disable=no-member
self
.
assertEqual
(
expected_short_date
,
actual_short_date
)
self
.
assertEqual
(
expected_date_time
,
actual_datetime
)
@patch
(
'util.date_utils.ugettext'
,
fake_ugettext
(
translations
=
{
"DATE_TIME_FORMAT"
:
"
%
b
%
d,
%
Y at
%
H:
%
M"
,
}))
def
test_end_datetime_no_due_date
(
self
):
"""verify that without a due date, the end date is an empty string"""
expected
=
''
actual
=
self
.
ccx
.
end_datetime_text
()
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
actual
=
self
.
ccx
.
end_datetime_text
(
'DATE_TIME'
)
# pylint: disable=no-member
self
.
assertEqual
(
expected
,
actual
)
def
test_ccx_max_student_enrollment_correct
(
self
):
"""
Verify the override value for max_student_enrollments_allowed
...
...
lms/djangoapps/learner_dashboard/views.py
View file @
1b2fbbd6
...
...
@@ -12,6 +12,7 @@ from openedx.core.djangoapps.catalog.utils import get_programs as get_catalog_pr
from
openedx.core.djangoapps.credentials.utils
import
get_programs_credentials
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
from
openedx.core.djangoapps.programs
import
utils
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preferences
@login_required
...
...
@@ -75,7 +76,8 @@ def program_details(request, program_id):
'show_program_listing'
:
programs_config
.
show_program_listing
,
'nav_hidden'
:
True
,
'disable_courseware_js'
:
True
,
'uses_pattern_library'
:
True
'uses_pattern_library'
:
True
,
'user_preferences'
:
get_user_preferences
(
request
.
user
)
}
return
render_to_response
(
'learner_dashboard/program_details.html'
,
context
)
lms/djangoapps/shoppingcart/models.py
View file @
1b2fbbd6
...
...
@@ -332,7 +332,7 @@ class Order(models.Model):
"""
this function generates the csv file
"""
course_
info
=
[]
course_
names
=
[]
csv_file
=
StringIO
.
StringIO
()
csv_writer
=
csv
.
writer
(
csv_file
)
csv_writer
.
writerow
([
'Course Name'
,
'Registration Code'
,
'URL'
])
...
...
@@ -340,15 +340,15 @@ class Order(models.Model):
course_id
=
item
.
course_id
course
=
get_course_by_id
(
item
.
course_id
,
depth
=
0
)
registration_codes
=
CourseRegistrationCode
.
objects
.
filter
(
course_id
=
course_id
,
order
=
self
)
course_
info
.
append
((
course
.
display_name
,
' ('
+
course
.
start_datetime_text
()
+
'-'
+
course
.
end_datetime_text
()
+
')'
)
)
course_
names
.
append
(
course
.
display_name
)
for
registration_code
in
registration_codes
:
redemption_url
=
reverse
(
'register_code_redemption'
,
args
=
[
registration_code
.
code
])
url
=
'{base_url}{redemption_url}'
.
format
(
base_url
=
site_name
,
redemption_url
=
redemption_url
)
csv_writer
.
writerow
([
unicode
(
course
.
display_name
)
.
encode
(
"utf-8"
),
registration_code
.
code
,
url
])
return
csv_file
,
course_
info
return
csv_file
,
course_
names
def
send_confirmation_emails
(
self
,
orderitems
,
is_order_type_business
,
csv_file
,
pdf_file
,
site_name
,
course
s_info
):
def
send_confirmation_emails
(
self
,
orderitems
,
is_order_type_business
,
csv_file
,
pdf_file
,
site_name
,
course
_names
):
"""
send confirmation e-mail
"""
...
...
@@ -358,8 +358,7 @@ class Order(models.Model):
joined_course_names
=
""
if
self
.
recipient_email
:
recipient_list
.
append
((
self
.
recipient_name
,
self
.
recipient_email
,
'email_recipient'
))
courses_names_with_dates
=
[
course_info
[
0
]
+
course_info
[
1
]
for
course_info
in
courses_info
]
joined_course_names
=
" "
+
", "
.
join
(
courses_names_with_dates
)
joined_course_names
=
" "
+
", "
.
join
(
course_names
)
if
not
is_order_type_business
:
subject
=
_
(
"Order Payment Confirmation"
)
...
...
@@ -387,7 +386,7 @@ class Order(models.Model):
'recipient_type'
:
recipient
[
2
],
'site_name'
:
site_name
,
'order_items'
:
orderitems
,
'course_names'
:
", "
.
join
(
[
course_info
[
0
]
for
course_info
in
courses_info
]
),
'course_names'
:
", "
.
join
(
course_names
),
'dashboard_url'
:
dashboard_url
,
'currency_symbol'
:
settings
.
PAID_COURSE_REGISTRATION_CURRENCY
[
1
],
'order_placed_by'
:
'{username} ({email})'
.
format
(
...
...
@@ -477,13 +476,13 @@ class Order(models.Model):
item
.
purchase_item
()
csv_file
=
None
course
s_info
=
[]
course
_names
=
[]
if
self
.
order_type
==
OrderTypes
.
BUSINESS
:
#
# Generate the CSV file that contains all of the RegistrationCodes that have already been
# generated when the purchase has transacted
#
csv_file
,
course
s_info
=
self
.
generate_registration_codes_csv
(
orderitems
,
site_name
)
csv_file
,
course
_names
=
self
.
generate_registration_codes_csv
(
orderitems
,
site_name
)
try
:
pdf_file
=
self
.
generate_pdf_receipt
(
orderitems
)
...
...
@@ -494,7 +493,7 @@ class Order(models.Model):
try
:
self
.
send_confirmation_emails
(
orderitems
,
self
.
order_type
==
OrderTypes
.
BUSINESS
,
csv_file
,
pdf_file
,
site_name
,
course
s_info
csv_file
,
pdf_file
,
site_name
,
course
_names
)
except
Exception
:
# pylint: disable=broad-except
# Catch all exceptions here, since the Django view implicitly
...
...
lms/djangoapps/verify_student/tests/test_views.py
View file @
1b2fbbd6
...
...
@@ -514,7 +514,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
response
,
unicode
(
course
.
id
),
course
.
display_name
,
course
.
start_datetime_text
(),
courseware_url
)
...
...
@@ -966,12 +965,11 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
else
:
self
.
assertFalse
(
displayed
,
msg
=
"Expected '{req}' requirement to be hidden"
.
format
(
req
=
req
))
def
_assert_course_details
(
self
,
response
,
course_key
,
display_name
,
start_text
,
url
):
def
_assert_course_details
(
self
,
response
,
course_key
,
display_name
,
url
):
"""Check the course information on the page. """
response_dict
=
self
.
_get_page_data
(
response
)
self
.
assertEqual
(
response_dict
[
'course_key'
],
course_key
)
self
.
assertEqual
(
response_dict
[
'course_name'
],
display_name
)
self
.
assertEqual
(
response_dict
[
'course_start_date'
],
start_text
)
self
.
assertEqual
(
response_dict
[
'courseware_url'
],
url
)
def
_assert_user_details
(
self
,
response
,
full_name
):
...
...
@@ -1001,7 +999,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
'full_name'
:
pay_and_verify_div
[
'data-full-name'
],
'course_key'
:
pay_and_verify_div
[
'data-course-key'
],
'course_name'
:
pay_and_verify_div
[
'data-course-name'
],
'course_start_date'
:
pay_and_verify_div
[
'data-course-start-date'
],
'courseware_url'
:
pay_and_verify_div
[
'data-courseware-url'
],
'course_mode_name'
:
pay_and_verify_div
[
'data-course-mode-name'
],
'course_mode_slug'
:
pay_and_verify_div
[
'data-course-mode-slug'
],
...
...
lms/static/js/discovery/discovery_factory.js
View file @
1b2fbbd6
...
...
@@ -5,17 +5,23 @@
'js/discovery/views/search_form'
,
'js/discovery/views/courses_listing'
,
'js/discovery/views/filter_bar'
,
'js/discovery/views/refine_sidebar'
],
function
(
Backbone
,
SearchState
,
Filters
,
SearchForm
,
CoursesListing
,
FilterBar
,
RefineSidebar
)
{
return
function
(
meanings
,
searchQuery
)
{
return
function
(
meanings
,
searchQuery
,
userLanguage
,
userTimezone
)
{
var
dispatcher
=
_
.
extend
({},
Backbone
.
Events
);
var
search
=
new
SearchState
();
var
filters
=
new
Filters
();
var
listing
=
new
CoursesListing
({
model
:
search
.
discovery
});
var
form
=
new
SearchForm
();
var
filterBar
=
new
FilterBar
({
collection
:
filters
});
var
refineSidebar
=
new
RefineSidebar
({
collection
:
search
.
discovery
.
facetOptions
,
meanings
:
meanings
});
var
listing
;
var
courseListingModel
=
search
.
discovery
;
courseListingModel
.
userPreferences
=
{
userLanguage
:
userLanguage
,
userTimezone
:
userTimezone
};
listing
=
new
CoursesListing
({
model
:
courseListingModel
});
dispatcher
.
listenTo
(
form
,
'search'
,
function
(
query
)
{
filters
.
reset
();
...
...
lms/static/js/discovery/views/course_card.js
View file @
1b2fbbd6
...
...
@@ -4,24 +4,19 @@
'underscore'
,
'backbone'
,
'gettext'
,
'
date
'
],
function
(
$
,
_
,
Backbone
,
gettext
,
Date
)
{
'
edx-ui-toolkit/js/utils/date-utils
'
],
function
(
$
,
_
,
Backbone
,
gettext
,
Date
Utils
)
{
'use strict'
;
function
formatDate
(
date
)
{
return
dateUTC
(
date
).
toString
(
'MMM dd, yyyy'
);
}
// Return a date object using UTC time instead of local time
function
dateUTC
(
date
)
{
return
new
Date
(
date
.
getUTCFullYear
(),
date
.
getUTCMonth
(),
date
.
getUTCDate
(),
date
.
getUTCHours
(),
date
.
getUTCMinutes
(),
date
.
getUTCSeconds
()
);
function
formatDate
(
date
,
userLanguage
,
userTimezone
)
{
var
context
;
context
=
{
datetime
:
date
,
language
:
userLanguage
,
timezone
:
userTimezone
,
format
:
DateUtils
.
dateFormatEnum
.
shortDate
};
return
DateUtils
.
localize
(
context
);
}
return
Backbone
.
View
.
extend
({
...
...
@@ -36,8 +31,26 @@
render
:
function
()
{
var
data
=
_
.
clone
(
this
.
model
.
attributes
);
data
.
start
=
formatDate
(
new
Date
(
data
.
start
));
data
.
enrollment_start
=
formatDate
(
new
Date
(
data
.
enrollment_start
));
var
userLanguage
=
''
,
userTimezone
=
''
;
if
(
this
.
model
.
userPreferences
!==
undefined
)
{
userLanguage
=
this
.
model
.
userPreferences
.
userLanguage
;
userTimezone
=
this
.
model
.
userPreferences
.
userTimezone
;
}
if
(
data
.
advertised_start
!==
undefined
)
{
data
.
start
=
data
.
advertised_start
;
}
else
{
data
.
start
=
formatDate
(
new
Date
(
data
.
start
),
userLanguage
,
userTimezone
);
}
data
.
enrollment_start
=
formatDate
(
new
Date
(
data
.
enrollment_start
),
userLanguage
,
userTimezone
);
this
.
$el
.
html
(
this
.
tpl
(
data
));
return
this
;
}
...
...
lms/static/js/discovery/views/courses_listing.js
View file @
1b2fbbd6
...
...
@@ -31,12 +31,15 @@
},
renderItems
:
function
()
{
/* eslint no-param-reassign: [2, { "props": true }] */
var
latest
=
this
.
model
.
latest
();
var
items
=
latest
.
map
(
function
(
result
)
{
result
.
userPreferences
=
this
.
model
.
userPreferences
;
var
item
=
new
CourseCardView
({
model
:
result
});
return
item
.
render
().
el
;
},
this
);
this
.
$list
.
append
(
items
);
/* eslint no-param-reassign: [2, { "props": false }] */
},
attachScrollHandler
:
function
()
{
...
...
lms/static/js/learner_dashboard/models/course_card_model.js
View file @
1b2fbbd6
...
...
@@ -4,14 +4,15 @@
(
function
(
define
)
{
'use strict'
;
define
([
'backbone'
'backbone'
,
'edx-ui-toolkit/js/utils/date-utils'
],
function
(
Backbone
)
{
function
(
Backbone
,
DateUtils
)
{
return
Backbone
.
Model
.
extend
({
initialize
:
function
(
data
)
{
if
(
data
)
{
this
.
context
=
data
;
this
.
setActiveRunMode
(
this
.
getRunMode
(
data
.
run_modes
));
this
.
setActiveRunMode
(
this
.
getRunMode
(
data
.
run_modes
)
,
data
.
user_preferences
);
}
},
...
...
@@ -31,7 +32,7 @@
var
enrolled_mode
=
_
.
findWhere
(
runModes
,
{
is_enrolled
:
true
}),
openEnrollmentRunModes
=
this
.
getEnrollableRunModes
(),
desiredRunMode
;
// We populate our model by looking at the run modes.
// We populate our model by looking at the run modes.
if
(
enrolled_mode
)
{
// If the learner is already enrolled in a run mode, return that one.
desiredRunMode
=
enrolled_mode
;
...
...
@@ -64,15 +65,44 @@
});
},
setActiveRunMode
:
function
(
runMode
)
{
formatDate
:
function
(
date
,
userPreferences
)
{
var
context
,
userTimezone
=
''
,
userLanguage
=
''
;
if
(
userPreferences
!==
undefined
)
{
userTimezone
=
userPreferences
.
time_zone
;
userLanguage
=
userPreferences
[
'pref-lang'
];
}
context
=
{
datetime
:
date
,
timezone
:
userTimezone
,
language
:
userLanguage
,
format
:
DateUtils
.
dateFormatEnum
.
shortDate
};
return
DateUtils
.
localize
(
context
);
},
setActiveRunMode
:
function
(
runMode
,
userPreferences
)
{
var
startDateString
;
if
(
runMode
)
{
if
(
runMode
.
advertised_start
!==
undefined
&&
runMode
.
advertised_start
!==
'None'
)
{
startDateString
=
runMode
.
advertised_start
;
}
else
{
startDateString
=
this
.
formatDate
(
runMode
.
start_date
,
userPreferences
);
}
this
.
set
({
certificate_url
:
runMode
.
certificate_url
,
course_image_url
:
runMode
.
course_image_url
||
''
,
course_key
:
runMode
.
course_key
,
course_url
:
runMode
.
course_url
||
''
,
display_name
:
this
.
context
.
display_name
,
end_date
:
runMode
.
end_date
,
end_date
:
this
.
formatDate
(
runMode
.
end_date
,
userPreferences
),
enrollable_run_modes
:
this
.
getEnrollableRunModes
(),
is_course_ended
:
runMode
.
is_course_ended
,
is_enrolled
:
runMode
.
is_enrolled
,
...
...
@@ -81,13 +111,12 @@
marketing_url
:
runMode
.
marketing_url
,
mode_slug
:
runMode
.
mode_slug
,
run_key
:
runMode
.
run_key
,
start_date
:
runMode
.
start_date
,
start_date
:
startDateString
,
upcoming_run_modes
:
this
.
getUpcomingRunModes
(),
upgrade_url
:
runMode
.
upgrade_url
});
}
},
setUnselected
:
function
()
{
// Called to reset the model back to the unselected state.
var
unselectedMode
=
this
.
getUnselectedRunMode
(
this
.
get
(
'enrollable_run_modes'
));
...
...
lms/static/js/learner_dashboard/views/program_details_view.js
View file @
1b2fbbd6
...
...
@@ -33,7 +33,8 @@
this
.
options
=
options
;
this
.
programModel
=
new
Backbone
.
Model
(
this
.
options
.
programData
);
this
.
courseCardCollection
=
new
CourseCardCollection
(
this
.
programModel
.
get
(
'course_codes'
)
this
.
programModel
.
get
(
'course_codes'
),
this
.
options
.
userPreferences
);
this
.
render
();
},
...
...
lms/static/js/spec/discovery/views/course_card_spec.js
View file @
1b2fbbd6
...
...
@@ -47,7 +47,7 @@ define([
expect
(
this
.
view
.
$el
.
find
(
'.course-name'
)).
toContainHtml
(
data
.
org
);
expect
(
this
.
view
.
$el
.
find
(
'.course-name'
)).
toContainHtml
(
data
.
content
.
number
);
expect
(
this
.
view
.
$el
.
find
(
'.course-name'
)).
toContainHtml
(
data
.
content
.
display_name
);
expect
(
this
.
view
.
$el
.
find
(
'.course-date'
)
).
toContainHtml
(
'Jan 0
1, 1970'
);
expect
(
this
.
view
.
$el
.
find
(
'.course-date'
)
.
text
().
trim
()).
toEqual
(
'Starts: Jan
1, 1970'
);
});
});
});
lms/static/js/spec/learner_dashboard/course_card_view_spec.js
View file @
1b2fbbd6
...
...
@@ -30,8 +30,9 @@ define([
context
.
run_modes
[
0
].
marketing_url
);
expect
(
view
.
$
(
'.course-details .course-text .course-key'
).
html
()).
toEqual
(
context
.
key
);
expect
(
view
.
$
(
'.course-details .course-text .run-period'
).
html
())
.
toEqual
(
context
.
run_modes
[
0
].
start_date
+
' - '
+
context
.
run_modes
[
0
].
end_date
);
expect
(
view
.
$
(
'.course-details .course-text .run-period'
).
html
()).
toEqual
(
context
.
run_modes
[
0
].
start_date
+
' - '
+
context
.
run_modes
[
0
].
end_date
);
};
beforeEach
(
function
()
{
...
...
@@ -92,6 +93,15 @@ define([
validateCourseInfoDisplay
();
});
it
(
'should show the course advertised start date'
,
function
()
{
var
advertisedStart
=
'This is an advertised start'
;
context
.
run_modes
[
0
].
advertised_start
=
advertisedStart
;
setupView
(
context
,
false
);
expect
(
view
.
$
(
'.course-details .course-text .run-period'
).
html
()).
toEqual
(
advertisedStart
+
' - '
+
context
.
run_modes
[
0
].
end_date
);
});
it
(
'should only show certificate status section if a certificate has been earned'
,
function
()
{
var
certUrl
=
'sample-certificate'
;
...
...
lms/static/js/verify_student/pay_and_verify.js
View file @
1b2fbbd6
...
...
@@ -75,7 +75,6 @@ var edx = edx || {};
'payment-confirmation-step'
:
{
courseKey
:
el
.
data
(
'course-key'
),
courseName
:
el
.
data
(
'course-name'
),
courseStartDate
:
el
.
data
(
'course-start-date'
),
coursewareUrl
:
el
.
data
(
'courseware-url'
),
platformName
:
el
.
data
(
'platform-name'
),
requirements
:
el
.
data
(
'requirements'
)
...
...
@@ -94,7 +93,6 @@ var edx = edx || {};
},
'enrollment-confirmation-step'
:
{
courseName
:
el
.
data
(
'course-name'
),
courseStartDate
:
el
.
data
(
'course-start-date'
),
coursewareUrl
:
el
.
data
(
'courseware-url'
),
platformName
:
el
.
data
(
'platform-name'
)
}
...
...
lms/static/js/verify_student/views/enrollment_confirmation_step_view.js
View file @
1b2fbbd6
...
...
@@ -23,7 +23,6 @@ var edx = edx || {};
defaultContext
:
function
()
{
return
{
courseName
:
''
,
courseStartDate
:
''
,
coursewareUrl
:
''
,
platformName
:
''
};
...
...
lms/static/js/verify_student/views/payment_confirmation_step_view.js
View file @
1b2fbbd6
...
...
@@ -16,7 +16,6 @@ var edx = edx || {};
return
{
courseKey
:
''
,
courseName
:
''
,
courseStartDate
:
''
,
coursewareUrl
:
''
,
platformName
:
''
,
requirements
:
[]
...
...
lms/templates/courseware/courses.html
View file @
1b2fbbd6
...
...
@@ -20,7 +20,9 @@
<
%
static:require_module
module_name=
"js/discovery/discovery_factory"
class_name=
"DiscoveryFactory"
>
DiscoveryFactory(
${course_discovery_meanings | n, dump_js_escaped_json},
getParameterByName('search_query')
getParameterByName('search_query'),
"${user_language}",
"${user_timezone}"
);
</
%
static:require
_module
>
</
%
block>
...
...
lms/templates/learner_dashboard/program_details.html
View file @
1b2fbbd6
...
...
@@ -16,6 +16,7 @@ from openedx.core.djangolib.js_utils import (
ProgramDetailsFactory({
programData: ${program_data | n, dump_js_escaped_json},
urls: ${urls | n, dump_js_escaped_json},
userPreferences: ${user_preferences | n, dump_js_escaped_json},
});
</
%
static:require
_module
>
</
%
block>
...
...
lms/templates/shoppingcart/receipt.html
View file @
1b2fbbd6
...
...
@@ -301,26 +301,6 @@ from openedx.core.lib.courses import course_image_url
<span
class=
"course-registration-title"
>
${_('Registration for:')}
</span>
<span
class=
"course-display-name"
>
${ course.display_name | h }
</span>
</h3>
<p
class=
"course-meta-info"
aria-describedby=
"course-title"
>
<span
class=
"course-dates-title"
>
<
%
course_start_time =
course.start_datetime_text()
course_end_time =
course.end_datetime_text()
%
>
% if course_start_time or course_end_time:
${_("Course Dates")}:
%endif
</span>
<span
class=
"course-display-dates"
>
% if course_start_time:
${course_start_time}
%endif
-
% if course_end_time:
${course_end_time}
%endif
</span>
</p>
<hr>
<div
class=
"three-col"
>
% if item.status == "purchased":
...
...
lms/templates/shoppingcart/registration_code_receipt.html
View file @
1b2fbbd6
...
...
@@ -34,12 +34,6 @@ from openedx.core.lib.courses import course_image_url
<div
class=
"course-title"
>
<h1>
${_("{course_name}").format(course_name=course.display_name) | h}
<span
class=
"course-dates"
>
${_("{start_date} - {end_date}").format(
start_date=course.start_datetime_text(),
end_date=course.end_datetime_text()
)}
</span>
</h1>
</div>
<hr>
...
...
lms/templates/shoppingcart/registration_code_redemption.html
View file @
1b2fbbd6
...
...
@@ -34,11 +34,6 @@ from openedx.core.lib.courses import course_image_url
<div
class=
"course-title"
>
<h1>
${course.display_name | h}
<span
class=
"course-dates"
>
${course.start_datetime_text()}
-
${course.end_datetime_text()}
</span>
</h1>
</div>
<hr>
...
...
lms/templates/shoppingcart/shopping_cart.html
View file @
1b2fbbd6
...
...
@@ -74,10 +74,6 @@ from openedx.core.lib.courses import course_image_url
<span
class=
"course-registration-title"
>
${_('Registration for:')}
</span>
<span
class=
"course-display-name"
>
${ course.display_name }
</span>
</h3>
<p
class=
"course-meta-info"
aria-describedby=
"course-title"
>
<span
class=
"course-dates-title"
>
${_('Course Dates:')}
</span>
<span
class=
"course-display-dates"
>
${ course.start_datetime_text() } - ${ course.end_datetime_text() }
</span>
</p>
<hr>
<div
class=
"three-col"
>
<div
class=
"col-1"
>
...
...
lms/templates/verify_student/enrollment_confirmation_step.underscore
View file @
1b2fbbd6
...
...
@@ -13,16 +13,14 @@
<thead>
<tr>
<th scope="col" ><%- gettext( "Course" ) %></th>
<th scope="col" ><
%- gettext( "Status" ) %><
/th>
<th scope="col" ></th>
</tr>
</thead>
<tbody>
<tr>
<td><%- courseName %></td>
<td>
<%- _.sprintf( gettext( "Starts: %(start)s" ), { start: courseStartDate } ) %>
</td>
<td></td>
</tr>
</tbody>
...
...
lms/templates/verify_student/pay_and_verify.html
View file @
1b2fbbd6
...
...
@@ -65,7 +65,6 @@ from lms.djangoapps.verify_student.views import PayAndVerifyView
data-platform-name=
'${platform_name}'
data-course-key=
'${course_key}'
data-course-name=
'${course.display_name}'
data-course-start-date=
'${course.start_datetime_text()}'
data-courseware-url=
'${courseware_url}'
data-course-mode-name=
'${course_mode.name}'
data-course-mode-slug=
'${course_mode.slug}'
...
...
@@ -124,6 +123,3 @@ from lms.djangoapps.verify_student.views import PayAndVerifyView
</section>
</div>
</
%
block>
<
%
static:require_module_async
module_name=
"js/dateutil_factory"
class_name=
"DateUtilFactory"
>
DateUtilFactory.transform(iterationKey=".localized-datetime");
</
%
static:require
_module_async
>
openedx/core/djangoapps/content/course_overviews/models.py
View file @
1b2fbbd6
...
...
@@ -9,7 +9,6 @@ from django.db import models, transaction
from
django.db.models.fields
import
BooleanField
,
DateTimeField
,
DecimalField
,
TextField
,
FloatField
,
IntegerField
from
django.db.utils
import
IntegrityError
from
django.template
import
defaultfilters
from
django.utils.translation
import
ugettext
from
ccx_keys.locator
import
CCXLocator
from
model_utils.models
import
TimeStampedModel
...
...
@@ -18,9 +17,7 @@ from opaque_keys.edx.keys import CourseKey
from
config_models.models
import
ConfigurationModel
from
lms.djangoapps
import
django_comment_client
from
openedx.core.djangoapps.models.course_details
import
CourseDetails
from
pytz
import
utc
from
static_replace.models
import
AssetBaseUrlConfig
from
util.date_utils
import
strftime_localized
from
xmodule
import
course_metadata_utils
,
block_metadata_utils
from
xmodule.course_module
import
CourseDescriptor
,
DEFAULT_START_DATE
from
xmodule.error_module
import
ErrorDescriptor
...
...
@@ -359,21 +356,6 @@ class CourseOverview(TimeStampedModel):
"""
return
course_metadata_utils
.
course_starts_within
(
self
.
start
,
days
)
def
start_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""
Returns the desired text corresponding to the course's start date and
time in the specified time zone, or utc if no time zone given.
Prefers .advertised_start, then falls back to .start.
"""
return
course_metadata_utils
.
course_start_datetime_text
(
self
.
start
,
self
.
advertised_start
,
format_string
,
time_zone
,
ugettext
,
strftime_localized
)
@property
def
start_date_is_still_default
(
self
):
"""
...
...
@@ -385,18 +367,6 @@ class CourseOverview(TimeStampedModel):
self
.
advertised_start
,
)
def
end_datetime_text
(
self
,
format_string
=
"SHORT_DATE"
,
time_zone
=
utc
):
"""
Returns the end date or datetime for the course formatted as a string.
"""
return
course_metadata_utils
.
course_end_datetime_text
(
self
.
end
,
format_string
,
time_zone
,
strftime_localized
)
@property
def
sorting_score
(
self
):
"""
...
...
openedx/core/djangoapps/content/course_overviews/tests.py
View file @
1b2fbbd6
...
...
@@ -127,10 +127,6 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
(
'clean_id'
,
(
'#'
,)),
(
'has_ended'
,
()),
(
'has_started'
,
()),
(
'start_datetime_text'
,
(
'SHORT_DATE'
,)),
(
'start_datetime_text'
,
(
'DATE_TIME'
,)),
(
'end_datetime_text'
,
(
'SHORT_DATE'
,)),
(
'end_datetime_text'
,
(
'DATE_TIME'
,)),
(
'may_certify'
,
()),
]
for
method_name
,
method_args
in
methods_to_test
:
...
...
openedx/core/djangoapps/programs/tests/test_utils.py
View file @
1b2fbbd6
...
...
@@ -11,7 +11,6 @@ from django.core.cache import cache
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django.test.utils
import
override_settings
from
django.utils
import
timezone
from
django.utils.text
import
slugify
import
httpretty
import
mock
...
...
@@ -19,6 +18,7 @@ from nose.plugins.attrib import attr
from
opaque_keys.edx.keys
import
CourseKey
from
edx_oauth2_provider.tests.factories
import
ClientFactory
from
provider.constants
import
CONFIDENTIAL
from
pytz
import
utc
from
lms.djangoapps.certificates.api
import
MODES
from
lms.djangoapps.commerce.tests.test_utils
import
update_commerce_config
...
...
@@ -718,8 +718,8 @@ class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase):
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
.
start
=
datetime
.
datetime
.
now
(
utc
)
-
datetime
.
timedelta
(
days
=
1
)
self
.
course
.
end
=
datetime
.
datetime
.
now
(
utc
)
+
datetime
.
timedelta
(
days
=
1
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
self
.
organization
=
factories
.
Organization
()
...
...
@@ -739,14 +739,15 @@ class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase):
course_image_url
=
course_overview
.
course_image_url
,
course_key
=
unicode
(
self
.
course
.
id
),
# pylint: disable=no-member
course_url
=
reverse
(
'course_root'
,
args
=
[
self
.
course
.
id
]),
# pylint: disable=no-member
end_date
=
s
trftime_localized
(
self
.
course
.
end
,
'SHORT_DATE'
),
end_date
=
s
elf
.
course
.
end
.
replace
(
tzinfo
=
utc
),
enrollment_open_date
=
strftime_localized
(
utils
.
DEFAULT_ENROLLMENT_START_DATE
,
'SHORT_DATE'
),
is_course_ended
=
self
.
course
.
end
<
timezone
.
now
(
),
is_course_ended
=
self
.
course
.
end
<
datetime
.
datetime
.
now
(
utc
),
is_enrolled
=
False
,
is_enrollment_open
=
True
,
marketing_url
=
MARKETING_URL
,
start_date
=
s
trftime_localized
(
self
.
course
.
start
,
'SHORT_DATE'
),
start_date
=
s
elf
.
course
.
start
.
replace
(
tzinfo
=
utc
),
upgrade_url
=
None
,
advertised_start
=
None
),
**
kwargs
)
...
...
@@ -828,8 +829,9 @@ class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase):
"""
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
.
enrollment_start
=
datetime
.
datetime
.
now
(
utc
)
-
datetime
.
timedelta
(
days
=
start_offset
)
self
.
course
.
enrollment_end
=
datetime
.
datetime
.
now
(
utc
)
-
datetime
.
timedelta
(
days
=
end_offset
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
data
=
utils
.
ProgramDataExtender
(
self
.
program
,
self
.
user
)
.
extend
()
...
...
@@ -845,7 +847,7 @@ class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase):
Regression test for ECOM-4973.
"""
self
.
course
.
enrollment_end
=
timezone
.
now
(
)
-
datetime
.
timedelta
(
days
=
1
)
self
.
course
.
enrollment_end
=
datetime
.
datetime
.
now
(
utc
)
-
datetime
.
timedelta
(
days
=
1
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
data
=
utils
.
ProgramDataExtender
(
self
.
program
,
self
.
user
)
.
extend
()
...
...
@@ -875,7 +877,7 @@ class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase):
@ddt.data
(
-
1
,
0
,
1
)
def
test_course_course_ended
(
self
,
days_offset
):
self
.
course
.
end
=
timezone
.
now
(
)
+
datetime
.
timedelta
(
days
=
days_offset
)
self
.
course
.
end
=
datetime
.
datetime
.
now
(
utc
)
+
datetime
.
timedelta
(
days
=
days_offset
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
# pylint: disable=no-member
data
=
utils
.
ProgramDataExtender
(
self
.
program
,
self
.
user
)
.
extend
()
...
...
openedx/core/djangoapps/programs/utils.py
View file @
1b2fbbd6
...
...
@@ -6,10 +6,9 @@ from urlparse import urljoin
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.utils
import
timezone
from
django.utils.text
import
slugify
from
opaque_keys.edx.keys
import
CourseKey
import
pytz
from
pytz
import
utc
from
course_modes.models
import
CourseMode
from
lms.djangoapps.certificates
import
api
as
certificate_api
...
...
@@ -30,7 +29,7 @@ from util.organizations_helpers import get_organization_by_short_name
log
=
logging
.
getLogger
(
__name__
)
# The datetime module's strftime() methods require a year >= 1900.
DEFAULT_ENROLLMENT_START_DATE
=
datetime
.
datetime
(
1900
,
1
,
1
,
tzinfo
=
pytz
.
UTC
)
DEFAULT_ENROLLMENT_START_DATE
=
datetime
.
datetime
(
1900
,
1
,
1
,
tzinfo
=
utc
)
def
get_programs
(
user
,
program_id
=
None
):
...
...
@@ -383,27 +382,30 @@ class ProgramDataExtender(object):
run_mode
[
'course_url'
]
=
reverse
(
'course_root'
,
args
=
[
self
.
course_key
])
def
_attach_run_mode_end_date
(
self
,
run_mode
):
run_mode
[
'end_date'
]
=
self
.
course_overview
.
end
_datetime_text
()
run_mode
[
'end_date'
]
=
self
.
course_overview
.
end
def
_attach_run_mode_enrollment_open_date
(
self
,
run_mode
):
run_mode
[
'enrollment_open_date'
]
=
strftime_localized
(
self
.
enrollment_start
,
'SHORT_DATE'
)
def
_attach_run_mode_is_course_ended
(
self
,
run_mode
):
end_date
=
self
.
course_overview
.
end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
pytz
.
UTC
)
run_mode
[
'is_course_ended'
]
=
end_date
<
timezone
.
now
(
)
end_date
=
self
.
course_overview
.
end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
utc
)
run_mode
[
'is_course_ended'
]
=
end_date
<
datetime
.
datetime
.
now
(
utc
)
def
_attach_run_mode_is_enrolled
(
self
,
run_mode
):
run_mode
[
'is_enrolled'
]
=
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course_key
)
def
_attach_run_mode_is_enrollment_open
(
self
,
run_mode
):
enrollment_end
=
self
.
course_overview
.
enrollment_end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
pytz
.
UTC
)
run_mode
[
'is_enrollment_open'
]
=
self
.
enrollment_start
<=
timezone
.
now
(
)
<
enrollment_end
enrollment_end
=
self
.
course_overview
.
enrollment_end
or
datetime
.
datetime
.
max
.
replace
(
tzinfo
=
utc
)
run_mode
[
'is_enrollment_open'
]
=
self
.
enrollment_start
<=
datetime
.
datetime
.
now
(
utc
)
<
enrollment_end
def
_attach_run_mode_marketing_url
(
self
,
run_mode
):
run_mode
[
'marketing_url'
]
=
get_run_marketing_url
(
self
.
course_key
,
self
.
user
)
def
_attach_run_mode_start_date
(
self
,
run_mode
):
run_mode
[
'start_date'
]
=
self
.
course_overview
.
start_datetime_text
()
run_mode
[
'start_date'
]
=
self
.
course_overview
.
start
def
_attach_run_mode_advertised_start
(
self
,
run_mode
):
run_mode
[
'advertised_start'
]
=
self
.
course_overview
.
advertised_start
def
_attach_run_mode_upgrade_url
(
self
,
run_mode
):
required_mode_slug
=
run_mode
[
'mode_slug'
]
...
...
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