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
24d6d377
Commit
24d6d377
authored
Aug 16, 2017
by
Diana Huang
Committed by
GitHub
Aug 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15789 from edx/diana/new-updates-behavior
Add new latest-update fragment and waffle flag.
parents
e9028ce8
dcf528a5
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
233 additions
and
56 deletions
+233
-56
lms/static/sass/features/_course-experience.scss
+2
-2
openedx/features/course_experience/__init__.py
+6
-0
openedx/features/course_experience/static/course_experience/fixtures/latest-update-fragment.html
+7
-0
openedx/features/course_experience/static/course_experience/js/LatestUpdate.js
+15
-0
openedx/features/course_experience/static/course_experience/js/spec/LatestUpdate_spec.js
+38
-0
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
+3
-3
openedx/features/course_experience/templates/course_experience/latest-update-fragment.html
+24
-0
openedx/features/course_experience/tests/views/test_course_updates.py
+2
-2
openedx/features/course_experience/tests/views/test_welcome_message.py
+30
-9
openedx/features/course_experience/urls.py
+6
-0
openedx/features/course_experience/views/course_home.py
+12
-5
openedx/features/course_experience/views/course_updates.py
+33
-33
openedx/features/course_experience/views/latest_update.py
+52
-0
openedx/features/course_experience/views/welcome_message.py
+2
-2
webpack.config.js
+1
-0
No files found.
lms/static/sass/features/_course-experience.scss
View file @
24d6d377
...
@@ -64,8 +64,8 @@
...
@@ -64,8 +64,8 @@
}
}
}
}
// Welcome message
// Welcome message
/ Latest Update message
.welcome-message
{
.welcome-message
,
.update-message
{
border
:
solid
1px
$lms-border-color
;
border
:
solid
1px
$lms-border-color
;
@include
border-left
(
solid
4px
$black
);
@include
border-left
(
solid
4px
$black
);
margin-bottom
:
$baseline
;
margin-bottom
:
$baseline
;
...
...
openedx/features/course_experience/__init__.py
View file @
24d6d377
...
@@ -25,6 +25,12 @@ COURSE_PRE_START_ACCESS_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'pre_star
...
@@ -25,6 +25,12 @@ COURSE_PRE_START_ACCESS_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'pre_star
# Waffle flag to enable a review page link from the unified home page
# Waffle flag to enable a review page link from the unified home page
SHOW_REVIEWS_TOOL_FLAG
=
CourseWaffleFlag
(
WAFFLE_FLAG_NAMESPACE
,
'show_reviews_tool'
)
SHOW_REVIEWS_TOOL_FLAG
=
CourseWaffleFlag
(
WAFFLE_FLAG_NAMESPACE
,
'show_reviews_tool'
)
# Waffle flag to switch between the 'welcome message' and 'latest update' on the course home page.
# Important Admin Note: This is meant to be configured using waffle_utils course
# override only. Either do not create the actual waffle flag, or be sure to unset the
# flag even for Superusers.
LATEST_UPDATE_FLAG
=
CourseWaffleFlag
(
WAFFLE_FLAG_NAMESPACE
,
'latest_update'
)
def
course_home_page_title
(
course
):
# pylint: disable=unused-argument
def
course_home_page_title
(
course
):
# pylint: disable=unused-argument
"""
"""
...
...
openedx/features/course_experience/static/course_experience/fixtures/latest-update-fragment.html
0 → 100644
View file @
24d6d377
<div
class=
"update-message"
>
<h3>
Latest Update
</h3>
<div
class=
"dismiss-message"
>
<button
type=
"button"
class=
"btn-link"
>
Dismiss
</button>
</div>
This is an update.
</div>
openedx/features/course_experience/static/course_experience/js/LatestUpdate.js
0 → 100644
View file @
24d6d377
/* globals $ */
import
'jquery.cookie'
;
export
class
LatestUpdate
{
// eslint-disable-line import/prefer-default-export
constructor
(
options
)
{
if
(
$
.
cookie
(
'update-message'
)
===
'hide'
)
{
$
(
options
.
messageContainer
).
hide
();
}
$
(
options
.
dismissButton
).
click
(()
=>
{
$
.
cookie
(
'update-message'
,
'hide'
,
{
expires
:
1
});
$
(
options
.
messageContainer
).
hide
();
});
}
}
openedx/features/course_experience/static/course_experience/js/spec/LatestUpdate_spec.js
0 → 100644
View file @
24d6d377
/* globals $, loadFixtures */
import
'jquery.cookie'
;
import
{
LatestUpdate
}
from
'../LatestUpdate'
;
describe
(
'LatestUpdate tests'
,
()
=>
{
function
createLatestUpdate
()
{
new
LatestUpdate
({
messageContainer
:
'.update-message'
,
dismissButton
:
'.dismiss-message button'
});
// eslint-disable-line no-new
}
describe
(
'Test dismiss'
,
()
=>
{
beforeEach
(()
=>
{
// This causes the cookie to be deleted.
$
.
cookie
(
'update-message'
,
''
,
{
expires
:
-
1
});
loadFixtures
(
'course_experience/fixtures/latest-update-fragment.html'
);
});
it
(
'Test dismiss button'
,
()
=>
{
expect
(
$
.
cookie
(
'update-message'
)).
toBe
(
null
);
createLatestUpdate
();
expect
(
$
(
'.update-message'
).
attr
(
'style'
)).
toBe
(
undefined
);
$
(
'.dismiss-message button'
).
click
();
expect
(
$
(
'.update-message'
).
attr
(
'style'
)).
toBe
(
'display: none;'
);
expect
(
$
.
cookie
(
'update-message'
)).
toBe
(
'hide'
);
});
it
(
'Test cookie hides update'
,
()
=>
{
$
.
cookie
(
'update-message'
,
'hide'
);
createLatestUpdate
();
expect
(
$
(
'.update-message'
).
attr
(
'style'
)).
toBe
(
'display: none;'
);
$
.
cookie
(
'update-message'
,
''
,
{
expires
:
-
1
});
loadFixtures
(
'course_experience/fixtures/latest-update-fragment.html'
);
createLatestUpdate
();
expect
(
$
(
'.update-message'
).
attr
(
'style'
)).
toBe
(
undefined
);
});
});
});
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
View file @
24d6d377
...
@@ -61,9 +61,9 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV
...
@@ -61,9 +61,9 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV
${HTML(course_home_message_fragment.body_html())}
${HTML(course_home_message_fragment.body_html())}
% endif
% endif
% if
welcom
e_message_fragment and UNIFIED_COURSE_TAB_FLAG.is_enabled(course.id):
% if
updat
e_message_fragment and UNIFIED_COURSE_TAB_FLAG.is_enabled(course.id):
<div
class=
"section section-
dates
"
>
<div
class=
"section section-
update-message
"
>
${HTML(
welcom
e_message_fragment.body_html())}
${HTML(
updat
e_message_fragment.body_html())}
</div>
</div>
% endif
% endif
...
...
openedx/features/course_experience/templates/course_experience/latest-update-fragment.html
0 → 100644
View file @
24d6d377
## mako
<
%
page
expression_filter=
"h"
/>
<
%
namespace
name=
'static'
file=
'../static_content.html'
/>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
from
openedx
.
core
.
djangolib
.
markup
import
HTML
%
>
<
%
block
name=
"content"
>
<div
class=
"update-message"
>
<div
class=
"dismiss-message"
>
<button
type=
"button"
class=
"btn-link"
>
${_("Dismiss")}
</button>
</div>
<h3>
${_("Latest Update")}
</h3>
${HTML(update_html)}
</div>
</
%
block>
<
%
static:webpack
entry=
"LatestUpdate"
>
new LatestUpdate( { messageContainer: '.update-message', dismissButton: '.dismiss-message button'});
</
%
static:webpack>
openedx/features/course_experience/tests/views/test_course_updates.py
View file @
24d6d377
...
@@ -4,7 +4,7 @@ Tests for the course updates page.
...
@@ -4,7 +4,7 @@ Tests for the course updates page.
from
courseware.courses
import
get_course_info_usage_key
from
courseware.courses
import
get_course_info_usage_key
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
openedx.core.djangoapps.waffle_utils.testutils
import
WAFFLE_TABLES
from
openedx.core.djangoapps.waffle_utils.testutils
import
WAFFLE_TABLES
from
openedx.features.course_experience.views.course_updates
import
CourseUpdatesFragmentView
from
openedx.features.course_experience.views.course_updates
import
STATUS_VISIBLE
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore
import
ModuleStoreEnum
...
@@ -43,7 +43,7 @@ def create_course_update(course, user, content, date='December 31, 1999'):
...
@@ -43,7 +43,7 @@ def create_course_update(course, user, content, date='December 31, 1999'):
"id"
:
len
(
course_updates
.
items
)
+
1
,
"id"
:
len
(
course_updates
.
items
)
+
1
,
"date"
:
date
,
"date"
:
date
,
"content"
:
content
,
"content"
:
content
,
"status"
:
CourseUpdatesFragmentView
.
STATUS_VISIBLE
"status"
:
STATUS_VISIBLE
})
})
modulestore
()
.
update_item
(
course_updates
,
user
.
id
)
modulestore
()
.
update_item
(
course_updates
,
user
.
id
)
...
...
openedx/features/course_experience/tests/views/test_welcome_message.py
View file @
24d6d377
"""
"""
Tests for course welcome messages.
Tests for course welcome messages.
"""
"""
import
ddt
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
...
@@ -27,6 +28,18 @@ def welcome_message_url(course):
...
@@ -27,6 +28,18 @@ def welcome_message_url(course):
)
)
def
latest_update_url
(
course
):
"""
Returns the URL for the latest update view.
"""
return
reverse
(
'openedx.course_experience.latest_update_fragment_view'
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
),
}
)
def
dismiss_message_url
(
course
):
def
dismiss_message_url
(
course
):
"""
"""
Returns the URL for the dismiss message endpoint.
Returns the URL for the dismiss message endpoint.
...
@@ -39,9 +52,12 @@ def dismiss_message_url(course):
...
@@ -39,9 +52,12 @@ def dismiss_message_url(course):
)
)
@ddt.ddt
class
TestWelcomeMessageView
(
ModuleStoreTestCase
):
class
TestWelcomeMessageView
(
ModuleStoreTestCase
):
"""
"""
Tests for the course welcome message fragment view.
Tests for the course welcome message fragment view.
Also tests the LatestUpdate view because the functionality is similar.
"""
"""
def
setUp
(
self
):
def
setUp
(
self
):
"""Set up the simplest course possible, then set up and enroll our fake user in the course."""
"""Set up the simplest course possible, then set up and enroll our fake user in the course."""
...
@@ -61,30 +77,35 @@ class TestWelcomeMessageView(ModuleStoreTestCase):
...
@@ -61,30 +77,35 @@ class TestWelcomeMessageView(ModuleStoreTestCase):
remove_course_updates
(
self
.
user
,
self
.
course
)
remove_course_updates
(
self
.
user
,
self
.
course
)
super
(
TestWelcomeMessageView
,
self
)
.
tearDown
()
super
(
TestWelcomeMessageView
,
self
)
.
tearDown
()
def
test_welcome_message
(
self
):
@ddt.data
(
welcome_message_url
,
latest_update_url
)
def
test_message_display
(
self
,
url_generator
):
create_course_update
(
self
.
course
,
self
.
user
,
'First Update'
,
date
=
'January 1, 2000'
)
create_course_update
(
self
.
course
,
self
.
user
,
'First Update'
,
date
=
'January 1, 2000'
)
create_course_update
(
self
.
course
,
self
.
user
,
'Second Update'
,
date
=
'January 1, 2017'
)
create_course_update
(
self
.
course
,
self
.
user
,
'Second Update'
,
date
=
'January 1, 2017'
)
create_course_update
(
self
.
course
,
self
.
user
,
'Retroactive Update'
,
date
=
'January 1, 2010'
)
create_course_update
(
self
.
course
,
self
.
user
,
'Retroactive Update'
,
date
=
'January 1, 2010'
)
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
response
=
self
.
client
.
get
(
url_generator
(
self
.
course
))
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertContains
(
response
,
'Second Update'
)
self
.
assertContains
(
response
,
'Second Update'
)
self
.
assertContains
(
response
,
'Dismiss'
)
self
.
assertContains
(
response
,
'Dismiss'
)
def
test_replace_urls
(
self
):
@ddt.data
(
welcome_message_url
,
latest_update_url
)
def
test_replace_urls
(
self
,
url_generator
):
img_url
=
'img.png'
img_url
=
'img.png'
create_course_update
(
self
.
course
,
self
.
user
,
"<img src='/static/{url}'>"
.
format
(
url
=
img_url
))
create_course_update
(
self
.
course
,
self
.
user
,
"<img src='/static/{url}'>"
.
format
(
url
=
img_url
))
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
response
=
self
.
client
.
get
(
url_generator
(
self
.
course
))
self
.
assertContains
(
response
,
"/asset-v1:{org}+{course}+{run}+type@asset+block/
img.png
"
.
format
(
self
.
assertContains
(
response
,
"/asset-v1:{org}+{course}+{run}+type@asset+block/
{url}
"
.
format
(
org
=
self
.
course
.
id
.
org
,
org
=
self
.
course
.
id
.
org
,
course
=
self
.
course
.
id
.
course
,
course
=
self
.
course
.
id
.
course
,
run
=
self
.
course
.
id
.
run
run
=
self
.
course
.
id
.
run
,
url
=
img_url
,
))
))
def
test_empty_welcome_message
(
self
):
@ddt.data
(
welcome_message_url
,
latest_update_url
)
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
def
test_empty_message
(
self
,
url_generator
):
response
=
self
.
client
.
get
(
url_generator
(
self
.
course
))
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assertEqual
(
response
.
status_code
,
204
)
def
test_dismiss_message
(
self
):
def
test_dismiss_welcome_message
(
self
):
# Latest update is dimssed in JS and has no server/backend component.
create_course_update
(
self
.
course
,
self
.
user
,
'First Update'
,
date
=
'January 1, 2017'
)
create_course_update
(
self
.
course
,
self
.
user
,
'First Update'
,
date
=
'January 1, 2017'
)
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
...
...
openedx/features/course_experience/urls.py
View file @
24d6d377
...
@@ -9,6 +9,7 @@ from views.course_outline import CourseOutlineFragmentView
...
@@ -9,6 +9,7 @@ from views.course_outline import CourseOutlineFragmentView
from
views.course_reviews
import
CourseReviewsView
from
views.course_reviews
import
CourseReviewsView
from
views.course_updates
import
CourseUpdatesFragmentView
,
CourseUpdatesView
from
views.course_updates
import
CourseUpdatesFragmentView
,
CourseUpdatesView
from
views.course_sock
import
CourseSockFragmentView
from
views.course_sock
import
CourseSockFragmentView
from
views.latest_update
import
LatestUpdateFragmentView
from
views.welcome_message
import
WelcomeMessageFragmentView
,
dismiss_welcome_message
from
views.welcome_message
import
WelcomeMessageFragmentView
,
dismiss_welcome_message
urlpatterns
=
[
urlpatterns
=
[
...
@@ -48,6 +49,11 @@ urlpatterns = [
...
@@ -48,6 +49,11 @@ urlpatterns = [
name
=
'openedx.course_experience.welcome_message_fragment_view'
,
name
=
'openedx.course_experience.welcome_message_fragment_view'
,
),
),
url
(
url
(
r'^latest_update_fragment$'
,
LatestUpdateFragmentView
.
as_view
(),
name
=
'openedx.course_experience.latest_update_fragment_view'
,
),
url
(
r'course_sock_fragment$'
,
r'course_sock_fragment$'
,
CourseSockFragmentView
.
as_view
(),
CourseSockFragmentView
.
as_view
(),
name
=
'openedx.course_experience.course_sock_fragment_view'
,
name
=
'openedx.course_experience.course_sock_fragment_view'
,
...
...
openedx/features/course_experience/views/course_home.py
View file @
24d6d377
...
@@ -24,11 +24,13 @@ from student.models import CourseEnrollment
...
@@ -24,11 +24,13 @@ from student.models import CourseEnrollment
from
util.views
import
ensure_valid_course_key
from
util.views
import
ensure_valid_course_key
from
web_fragments.fragment
import
Fragment
from
web_fragments.fragment
import
Fragment
from
..
import
LATEST_UPDATE_FLAG
from
..utils
import
get_course_outline_block_tree
from
..utils
import
get_course_outline_block_tree
from
.course_dates
import
CourseDatesFragmentView
from
.course_dates
import
CourseDatesFragmentView
from
.course_home_messages
import
CourseHomeMessageFragmentView
from
.course_home_messages
import
CourseHomeMessageFragmentView
from
.course_outline
import
CourseOutlineFragmentView
from
.course_outline
import
CourseOutlineFragmentView
from
.course_sock
import
CourseSockFragmentView
from
.course_sock
import
CourseSockFragmentView
from
.latest_update
import
LatestUpdateFragmentView
from
.welcome_message
import
WelcomeMessageFragmentView
from
.welcome_message
import
WelcomeMessageFragmentView
EMPTY_HANDOUTS_HTML
=
u'<ol></ol>'
EMPTY_HANDOUTS_HTML
=
u'<ol></ol>'
...
@@ -121,9 +123,14 @@ class CourseHomeFragmentView(EdxFragmentView):
...
@@ -121,9 +123,14 @@ class CourseHomeFragmentView(EdxFragmentView):
}
}
if
user_access
[
'is_enrolled'
]
or
user_access
[
'is_staff'
]:
if
user_access
[
'is_enrolled'
]
or
user_access
[
'is_staff'
]:
outline_fragment
=
CourseOutlineFragmentView
()
.
render_to_fragment
(
request
,
course_id
=
course_id
,
**
kwargs
)
outline_fragment
=
CourseOutlineFragmentView
()
.
render_to_fragment
(
request
,
course_id
=
course_id
,
**
kwargs
)
welcome_message_fragment
=
WelcomeMessageFragmentView
()
.
render_to_fragment
(
if
LATEST_UPDATE_FLAG
.
is_enabled
(
course_key
):
request
,
course_id
=
course_id
,
**
kwargs
update_message_fragment
=
LatestUpdateFragmentView
()
.
render_to_fragment
(
)
request
,
course_id
=
course_id
,
**
kwargs
)
else
:
update_message_fragment
=
WelcomeMessageFragmentView
()
.
render_to_fragment
(
request
,
course_id
=
course_id
,
**
kwargs
)
course_sock_fragment
=
CourseSockFragmentView
()
.
render_to_fragment
(
request
,
course
=
course
,
**
kwargs
)
course_sock_fragment
=
CourseSockFragmentView
()
.
render_to_fragment
(
request
,
course
=
course
,
**
kwargs
)
has_visited_course
,
resume_course_url
=
self
.
_get_resume_course_info
(
request
,
course_id
)
has_visited_course
,
resume_course_url
=
self
.
_get_resume_course_info
(
request
,
course_id
)
else
:
else
:
...
@@ -134,7 +141,7 @@ class CourseHomeFragmentView(EdxFragmentView):
...
@@ -134,7 +141,7 @@ class CourseHomeFragmentView(EdxFragmentView):
# Set all the fragments
# Set all the fragments
outline_fragment
=
None
outline_fragment
=
None
welcom
e_message_fragment
=
None
updat
e_message_fragment
=
None
course_sock_fragment
=
None
course_sock_fragment
=
None
has_visited_course
=
None
has_visited_course
=
None
resume_course_url
=
None
resume_course_url
=
None
...
@@ -163,7 +170,7 @@ class CourseHomeFragmentView(EdxFragmentView):
...
@@ -163,7 +170,7 @@ class CourseHomeFragmentView(EdxFragmentView):
'resume_course_url'
:
resume_course_url
,
'resume_course_url'
:
resume_course_url
,
'course_tools'
:
course_tools
,
'course_tools'
:
course_tools
,
'dates_fragment'
:
dates_fragment
,
'dates_fragment'
:
dates_fragment
,
'
welcome_message_fragment'
:
welcom
e_message_fragment
,
'
update_message_fragment'
:
updat
e_message_fragment
,
'course_sock_fragment'
:
course_sock_fragment
,
'course_sock_fragment'
:
course_sock_fragment
,
'disable_courseware_js'
:
True
,
'disable_courseware_js'
:
True
,
'uses_pattern_library'
:
True
,
'uses_pattern_library'
:
True
,
...
...
openedx/features/course_experience/views/course_updates.py
View file @
24d6d377
...
@@ -17,6 +17,37 @@ from lms.djangoapps.courseware.views.views import CourseTabView
...
@@ -17,6 +17,37 @@ from lms.djangoapps.courseware.views.views import CourseTabView
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.features.course_experience
import
default_course_url_name
from
openedx.features.course_experience
import
default_course_url_name
STATUS_VISIBLE
=
'visible'
STATUS_DELETED
=
'deleted'
def
get_ordered_updates
(
request
,
course
):
"""
Returns any course updates in reverse chronological order.
"""
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
updates
=
info_module
.
items
if
info_module
else
[]
info_block
=
getattr
(
info_module
,
'_xmodule'
,
info_module
)
if
info_module
else
None
ordered_updates
=
[
update
for
update
in
updates
if
update
.
get
(
'status'
)
==
STATUS_VISIBLE
]
ordered_updates
.
sort
(
key
=
lambda
item
:
(
safe_parse_date
(
item
[
'date'
]),
item
[
'id'
]),
reverse
=
True
)
for
update
in
ordered_updates
:
update
[
'content'
]
=
info_block
.
system
.
replace_urls
(
update
[
'content'
])
return
ordered_updates
def
safe_parse_date
(
date
):
"""
Since this is used solely for ordering purposes, use today's date as a default
"""
try
:
return
datetime
.
strptime
(
date
,
'
%
B
%
d,
%
Y'
)
except
ValueError
:
# occurs for ill-formatted date values
return
datetime
.
today
()
class
CourseUpdatesView
(
CourseTabView
):
class
CourseUpdatesView
(
CourseTabView
):
"""
"""
...
@@ -41,9 +72,6 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -41,9 +72,6 @@ class CourseUpdatesFragmentView(EdxFragmentView):
"""
"""
A fragment to render the updates page for a course.
A fragment to render the updates page for a course.
"""
"""
STATUS_VISIBLE
=
'visible'
STATUS_DELETED
=
'deleted'
def
render_to_fragment
(
self
,
request
,
course_id
=
None
,
**
kwargs
):
def
render_to_fragment
(
self
,
request
,
course_id
=
None
,
**
kwargs
):
"""
"""
Renders the course's home page as a fragment.
Renders the course's home page as a fragment.
...
@@ -53,7 +81,7 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -53,7 +81,7 @@ class CourseUpdatesFragmentView(EdxFragmentView):
course_url_name
=
default_course_url_name
(
course
.
id
)
course_url_name
=
default_course_url_name
(
course
.
id
)
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
ordered_updates
=
self
.
get_ordered_updates
(
request
,
course
)
ordered_updates
=
get_ordered_updates
(
request
,
course
)
plain_html_updates
=
''
plain_html_updates
=
''
if
ordered_updates
:
if
ordered_updates
:
plain_html_updates
=
self
.
get_plain_html_updates
(
request
,
course
)
plain_html_updates
=
self
.
get_plain_html_updates
(
request
,
course
)
...
@@ -72,26 +100,8 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -72,26 +100,8 @@ class CourseUpdatesFragmentView(EdxFragmentView):
return
Fragment
(
html
)
return
Fragment
(
html
)
@classmethod
@classmethod
def
get_ordered_updates
(
self
,
request
,
course
):
"""
Returns any course updates in reverse chronological order.
"""
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
updates
=
info_module
.
items
if
info_module
else
[]
info_block
=
getattr
(
info_module
,
'_xmodule'
,
info_module
)
if
info_module
else
None
ordered_updates
=
[
update
for
update
in
updates
if
update
.
get
(
'status'
)
==
self
.
STATUS_VISIBLE
]
ordered_updates
.
sort
(
key
=
lambda
item
:
(
self
.
safe_parse_date
(
item
[
'date'
]),
item
[
'id'
]),
reverse
=
True
)
for
update
in
ordered_updates
:
update
[
'content'
]
=
info_block
.
system
.
replace_urls
(
update
[
'content'
])
return
ordered_updates
@classmethod
def
has_updates
(
self
,
request
,
course
):
def
has_updates
(
self
,
request
,
course
):
return
len
(
self
.
get_ordered_updates
(
request
,
course
))
>
0
return
len
(
get_ordered_updates
(
request
,
course
))
>
0
@classmethod
@classmethod
def
get_plain_html_updates
(
self
,
request
,
course
):
def
get_plain_html_updates
(
self
,
request
,
course
):
...
@@ -103,13 +113,3 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -103,13 +113,3 @@ class CourseUpdatesFragmentView(EdxFragmentView):
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
info_block
=
getattr
(
info_module
,
'_xmodule'
,
info_module
)
info_block
=
getattr
(
info_module
,
'_xmodule'
,
info_module
)
return
info_block
.
system
.
replace_urls
(
info_module
.
data
)
if
info_module
else
''
return
info_block
.
system
.
replace_urls
(
info_module
.
data
)
if
info_module
else
''
@staticmethod
def
safe_parse_date
(
date
):
"""
Since this is used solely for ordering purposes, use today's date as a default
"""
try
:
return
datetime
.
strptime
(
date
,
'
%
B
%
d,
%
Y'
)
except
ValueError
:
# occurs for ill-formatted date values
return
datetime
.
today
()
openedx/features/course_experience/views/latest_update.py
0 → 100644
View file @
24d6d377
"""
View logic for handling latest course updates.
Although the welcome message fragment also displays the latest update,
this fragment dismisses the message for a limited time so new updates
will continue to appear, where the welcome message gets permanently
dismissed.
"""
from
django.template.loader
import
render_to_string
from
opaque_keys.edx.keys
import
CourseKey
from
web_fragments.fragment
import
Fragment
from
courseware.courses
import
get_course_with_access
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.features.course_experience.views.course_updates
import
get_ordered_updates
class
LatestUpdateFragmentView
(
EdxFragmentView
):
"""
A fragment that displays the latest course update.
"""
def
render_to_fragment
(
self
,
request
,
course_id
=
None
,
**
kwargs
):
"""
Renders the latest update message fragment for the specified course.
Returns: A fragment, or None if there is no latest update message.
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
update_html
=
self
.
latest_update_html
(
request
,
course
)
if
not
update_html
:
return
None
context
=
{
'update_html'
:
update_html
,
}
html
=
render_to_string
(
'course_experience/latest-update-fragment.html'
,
context
)
return
Fragment
(
html
)
@classmethod
def
latest_update_html
(
cls
,
request
,
course
):
"""
Returns the course's latest update message or None if it doesn't have one.
"""
# Return the course update with the most recent publish date
ordered_updates
=
get_ordered_updates
(
request
,
course
)
content
=
None
if
ordered_updates
:
content
=
ordered_updates
[
0
][
'content'
]
return
content
openedx/features/course_experience/views/welcome_message.py
View file @
24d6d377
...
@@ -9,7 +9,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie
...
@@ -9,7 +9,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.keys
import
CourseKey
from
web_fragments.fragment
import
Fragment
from
web_fragments.fragment
import
Fragment
from
course_updates
import
CourseUpdatesFragmentView
from
course_updates
import
get_ordered_updates
from
courseware.courses
import
get_course_info_section_module
,
get_course_with_access
from
courseware.courses
import
get_course_info_section_module
,
get_course_with_access
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.core.djangoapps.user_api.course_tag.api
import
set_course_tag
,
get_course_tag
from
openedx.core.djangoapps.user_api.course_tag.api
import
set_course_tag
,
get_course_tag
...
@@ -54,7 +54,7 @@ class WelcomeMessageFragmentView(EdxFragmentView):
...
@@ -54,7 +54,7 @@ class WelcomeMessageFragmentView(EdxFragmentView):
Returns the course's welcome message or None if it doesn't have one.
Returns the course's welcome message or None if it doesn't have one.
"""
"""
# Return the course update with the most recent publish date
# Return the course update with the most recent publish date
ordered_updates
=
CourseUpdatesFragmentView
.
get_ordered_updates
(
request
,
course
)
ordered_updates
=
get_ordered_updates
(
request
,
course
)
content
=
None
content
=
None
if
ordered_updates
:
if
ordered_updates
:
content
=
ordered_updates
[
0
][
'content'
]
content
=
ordered_updates
[
0
][
'content'
]
...
...
webpack.config.js
View file @
24d6d377
...
@@ -22,6 +22,7 @@ var wpconfig = {
...
@@ -22,6 +22,7 @@ var wpconfig = {
CourseOutline
:
'./openedx/features/course_experience/static/course_experience/js/CourseOutline.js'
,
CourseOutline
:
'./openedx/features/course_experience/static/course_experience/js/CourseOutline.js'
,
CourseSock
:
'./openedx/features/course_experience/static/course_experience/js/CourseSock.js'
,
CourseSock
:
'./openedx/features/course_experience/static/course_experience/js/CourseSock.js'
,
CourseTalkReviews
:
'./openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js'
,
CourseTalkReviews
:
'./openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js'
,
LatestUpdate
:
'./openedx/features/course_experience/static/course_experience/js/LatestUpdate.js'
,
WelcomeMessage
:
'./openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js'
,
WelcomeMessage
:
'./openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js'
,
Enrollment
:
'./openedx/features/course_experience/static/course_experience/js/Enrollment.js'
,
Enrollment
:
'./openedx/features/course_experience/static/course_experience/js/Enrollment.js'
,
Import
:
'./cms/static/js/features/import/factories/import.js'
,
Import
:
'./cms/static/js/features/import/factories/import.js'
,
...
...
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