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
e6c94400
Commit
e6c94400
authored
Jun 26, 2017
by
Harry Rein
Committed by
GitHub
Jun 26, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15406 from edx/HarryRein/LEARNER-1534-no-updates-bug
Only display updates course tool when updates exist.
parents
330c4daa
a34081c2
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
87 additions
and
52 deletions
+87
-52
openedx/features/course_bookmarks/plugins.py
+1
-1
openedx/features/course_experience/course_tools.py
+1
-1
openedx/features/course_experience/plugins.py
+10
-6
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
+1
-1
openedx/features/course_experience/templates/course_experience/course-updates-fragment.html
+16
-10
openedx/features/course_experience/tests/views/test_course_home.py
+25
-9
openedx/features/course_experience/tests/views/test_course_updates.py
+3
-2
openedx/features/course_experience/tests/views/test_welcome_message.py
+1
-1
openedx/features/course_experience/views/course_home.py
+2
-6
openedx/features/course_experience/views/course_updates.py
+25
-10
openedx/features/course_experience/views/welcome_message.py
+2
-5
No files found.
openedx/features/course_bookmarks/plugins.py
View file @
e6c94400
...
@@ -12,7 +12,7 @@ class CourseBookmarksTool(CourseTool):
...
@@ -12,7 +12,7 @@ class CourseBookmarksTool(CourseTool):
The course bookmarks tool.
The course bookmarks tool.
"""
"""
@classmethod
@classmethod
def
is_enabled
(
cls
,
course_key
):
def
is_enabled
(
cls
,
request
,
course_key
):
"""
"""
Always show the bookmarks tool.
Always show the bookmarks tool.
"""
"""
...
...
openedx/features/course_experience/course_tools.py
View file @
e6c94400
...
@@ -18,7 +18,7 @@ class CourseTool(object):
...
@@ -18,7 +18,7 @@ class CourseTool(object):
"""
"""
@classmethod
@classmethod
def
is_enabled
(
cls
,
course_key
):
def
is_enabled
(
cls
,
request
,
course_key
):
"""
"""
Returns true if this tool is enabled for the specified course key.
Returns true if this tool is enabled for the specified course key.
"""
"""
...
...
openedx/features/course_experience/plugins.py
View file @
e6c94400
...
@@ -3,13 +3,15 @@ Platform plugins to support the course experience.
...
@@ -3,13 +3,15 @@ Platform plugins to support the course experience.
This includes any locally defined CourseTools.
This includes any locally defined CourseTools.
"""
"""
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
.
import
UNIFIED_COURSE_TAB_FLAG
,
SHOW_REVIEWS_TOOL_FLAG
from
views.course_reviews
import
CourseReviewsModuleFragmentView
from
course_tools
import
CourseTool
from
course_tools
import
CourseTool
from
courseware.courses
import
get_course_by_id
from
views.course_reviews
import
CourseReviewsModuleFragmentView
from
views.course_updates
import
CourseUpdatesFragmentView
from
.
import
SHOW_REVIEWS_TOOL_FLAG
,
UNIFIED_COURSE_TAB_FLAG
class
CourseUpdatesTool
(
CourseTool
):
class
CourseUpdatesTool
(
CourseTool
):
...
@@ -31,11 +33,13 @@ class CourseUpdatesTool(CourseTool):
...
@@ -31,11 +33,13 @@ class CourseUpdatesTool(CourseTool):
return
'fa fa-newspaper-o'
return
'fa fa-newspaper-o'
@classmethod
@classmethod
def
is_enabled
(
cls
,
course_key
):
def
is_enabled
(
cls
,
request
,
course_key
):
"""
"""
Returns True if this tool is enabled for the specified course key.
Returns True if this tool is enabled for the specified course key.
"""
"""
return
UNIFIED_COURSE_TAB_FLAG
.
is_enabled
(
course_key
)
course
=
get_course_by_id
(
course_key
)
has_updates
=
CourseUpdatesFragmentView
.
has_updates
(
request
,
course
)
return
UNIFIED_COURSE_TAB_FLAG
.
is_enabled
(
course_key
)
and
has_updates
@classmethod
@classmethod
def
url
(
cls
,
course_key
):
def
url
(
cls
,
course_key
):
...
@@ -64,7 +68,7 @@ class CourseReviewsTool(CourseTool):
...
@@ -64,7 +68,7 @@ class CourseReviewsTool(CourseTool):
return
'fa fa-star'
return
'fa fa-star'
@classmethod
@classmethod
def
is_enabled
(
cls
,
course_key
):
def
is_enabled
(
cls
,
request
,
course_key
):
"""
"""
Returns True if this tool is enabled for the specified course key.
Returns True if this tool is enabled for the specified course key.
"""
"""
...
...
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
View file @
e6c94400
...
@@ -75,7 +75,7 @@ from openedx.features.course_experience.course_tools import CourseToolsPluginMan
...
@@ -75,7 +75,7 @@ from openedx.features.course_experience.course_tools import CourseToolsPluginMan
<h3
class=
"hd-6"
>
${_("Course Tools")}
</h3>
<h3
class=
"hd-6"
>
${_("Course Tools")}
</h3>
<ul
class=
"list-unstyled"
>
<ul
class=
"list-unstyled"
>
% for course_tool in course_tools:
% for course_tool in course_tools:
% if course_tool.is_enabled(course_key):
% if course_tool.is_enabled(
request,
course_key):
<li>
<li>
<a
href=
"${course_tool.url(course_key)}"
>
<a
href=
"${course_tool.url(course_key)}"
>
<span
class=
"icon ${course_tool.icon_classes()}"
aria-hidden=
"true"
></span>
<span
class=
"icon ${course_tool.icon_classes()}"
aria-hidden=
"true"
></span>
...
...
openedx/features/course_experience/templates/course_experience/course-updates-fragment.html
View file @
e6c94400
...
@@ -29,20 +29,26 @@ from openedx.features.course_experience import course_home_page_title
...
@@ -29,20 +29,26 @@ from openedx.features.course_experience import course_home_page_title
</div>
</div>
</header>
</header>
<div
class=
"page-content"
>
<div
class=
"page-content"
>
% if
len(plain_html_updates) > 0
:
% if
plain_html_updates
:
${HTML(plain_html_updates)}
${HTML(plain_html_updates)}
% else:
% else:
<div
class=
"all-updates"
>
<div
class=
"all-updates"
>
% for index, update in enumerate(updates):
% if updates:
<article
class=
"updates-article"
>
% for index, update in enumerate(updates):
% if not update.get("is_error"):
<article
class=
"updates-article"
>
<div
class=
"date"
>
${update.get("date")}
</div>
% if not update.get("is_error"):
% endif
<div
class=
"date"
>
${update.get("date")}
</div>
<div
class=
"article-content"
>
% endif
${HTML(update.get("content"))}
<div
class=
"article-content"
>
${HTML(update.get("content"))}
</div>
</article>
% endfor
% else:
<div
class=
"well depth-0 message-area"
>
${_("This course does not have any updates.")}
</div>
</div>
</article>
% endif
% endfor
</div>
</div>
% endif
% endif
</div>
</div>
...
...
openedx/features/course_experience/tests/views/test_course_home.py
View file @
e6c94400
...
@@ -16,6 +16,8 @@ from .test_course_updates import create_course_update, remove_course_updates
...
@@ -16,6 +16,8 @@ from .test_course_updates import create_course_update, remove_course_updates
TEST_PASSWORD
=
'test'
TEST_PASSWORD
=
'test'
TEST_WELCOME_MESSAGE
=
'<h2>Welcome!</h2>'
TEST_WELCOME_MESSAGE
=
'<h2>Welcome!</h2>'
TEST_UPDATE_MESSAGE
=
'<h2>Test Update!</h2>'
TEST_COURSE_UPDATES_TOOL
=
'/course/updates">'
def
course_home_url
(
course
):
def
course_home_url
(
course
):
...
@@ -55,9 +57,6 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
...
@@ -55,9 +57,6 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
# Create a welcome message
create_course_update
(
cls
.
course
,
cls
.
user
,
TEST_WELCOME_MESSAGE
)
def
setUp
(
self
):
def
setUp
(
self
):
"""
"""
Set up for the tests.
Set up for the tests.
...
@@ -65,22 +64,39 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
...
@@ -65,22 +64,39 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
super
(
TestCourseHomePage
,
self
)
.
setUp
()
super
(
TestCourseHomePage
,
self
)
.
setUp
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
super
(
TestCourseHomePage
,
self
)
.
tearDown
()
@override_waffle_flag
(
UNIFIED_COURSE_TAB_FLAG
,
active
=
True
)
@override_waffle_flag
(
UNIFIED_COURSE_TAB_FLAG
,
active
=
True
)
def
test_welcome_message_when_unified
(
self
):
def
test_welcome_message_when_unified
(
self
):
# Create a welcome message
create_course_update
(
self
.
course
,
self
.
user
,
TEST_WELCOME_MESSAGE
)
url
=
course_home_url
(
self
.
course
)
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
self
.
assertContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
@override_waffle_flag
(
UNIFIED_COURSE_TAB_FLAG
,
active
=
False
)
@override_waffle_flag
(
UNIFIED_COURSE_TAB_FLAG
,
active
=
False
)
def
test_welcome_message_when_not_unified
(
self
):
def
test_welcome_message_when_not_unified
(
self
):
# Create a welcome message
create_course_update
(
self
.
course
,
self
.
user
,
TEST_WELCOME_MESSAGE
)
url
=
course_home_url
(
self
.
course
)
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertNotContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
self
.
assertNotContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
@override_waffle_flag
(
UNIFIED_COURSE_TAB_FLAG
,
active
=
True
)
def
test_updates_tool_visibility
(
self
):
"""
Verify that the updates course tool is visible only when the course
has one or more updates.
"""
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
self
.
assertNotContains
(
response
,
TEST_COURSE_UPDATES_TOOL
,
status_code
=
200
)
create_course_update
(
self
.
course
,
self
.
user
,
TEST_UPDATE_MESSAGE
)
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
self
.
assertContains
(
response
,
TEST_COURSE_UPDATES_TOOL
,
status_code
=
200
)
def
test_queries
(
self
):
def
test_queries
(
self
):
"""
"""
Verify that the view's query count doesn't regress.
Verify that the view's query count doesn't regress.
...
@@ -89,7 +105,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
...
@@ -89,7 +105,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
course_home_url
(
self
.
course
)
course_home_url
(
self
.
course
)
# Fetch the view and verify the query counts
# Fetch the view and verify the query counts
with
self
.
assertNumQueries
(
51
):
with
self
.
assertNumQueries
(
46
):
with
check_mongo_calls
(
5
):
with
check_mongo_calls
(
4
):
url
=
course_home_url
(
self
.
course
)
url
=
course_home_url
(
self
.
course
)
self
.
client
.
get
(
url
)
self
.
client
.
get
(
url
)
openedx/features/course_experience/tests/views/test_course_updates.py
View file @
e6c94400
...
@@ -61,7 +61,7 @@ def create_course_updates_block(course, user):
...
@@ -61,7 +61,7 @@ def create_course_updates_block(course, user):
return
course_updates
return
course_updates
def
remove_course_updates
(
course
):
def
remove_course_updates
(
user
,
course
):
"""
"""
Remove any course updates in the specified course.
Remove any course updates in the specified course.
"""
"""
...
@@ -69,6 +69,7 @@ def remove_course_updates(course):
...
@@ -69,6 +69,7 @@ def remove_course_updates(course):
try
:
try
:
course_updates
=
modulestore
()
.
get_item
(
updates_usage_key
)
course_updates
=
modulestore
()
.
get_item
(
updates_usage_key
)
course_updates
.
items
=
[]
course_updates
.
items
=
[]
modulestore
()
.
update_item
(
course_updates
,
user
.
id
)
except
ItemNotFoundError
:
except
ItemNotFoundError
:
pass
pass
...
@@ -105,7 +106,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
...
@@ -105,7 +106,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
remove_course_updates
(
self
.
user
,
self
.
course
)
super
(
TestCourseUpdatesPage
,
self
)
.
tearDown
()
super
(
TestCourseUpdatesPage
,
self
)
.
tearDown
()
def
test_view
(
self
):
def
test_view
(
self
):
...
...
openedx/features/course_experience/tests/views/test_welcome_message.py
View file @
e6c94400
...
@@ -58,7 +58,7 @@ class TestWelcomeMessageView(ModuleStoreTestCase):
...
@@ -58,7 +58,7 @@ class TestWelcomeMessageView(ModuleStoreTestCase):
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
remove_course_updates
(
self
.
user
,
self
.
course
)
super
(
TestWelcomeMessageView
,
self
)
.
tearDown
()
super
(
TestWelcomeMessageView
,
self
)
.
tearDown
()
def
test_welcome_message
(
self
):
def
test_welcome_message
(
self
):
...
...
openedx/features/course_experience/views/course_home.py
View file @
e6c94400
...
@@ -19,9 +19,8 @@ from util.views import ensure_valid_course_key
...
@@ -19,9 +19,8 @@ from util.views import ensure_valid_course_key
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_outline
import
CourseOutlineFragmentView
from
.course_outline
import
CourseOutlineFragmentView
from
.course_reviews
import
CourseReviewsModuleFragmentView
from
.welcome_message
import
WelcomeMessageFragmentView
from
.course_sock
import
CourseSockFragmentView
from
.course_sock
import
CourseSockFragmentView
from
.welcome_message
import
WelcomeMessageFragmentView
class
CourseHomeView
(
CourseTabView
):
class
CourseHomeView
(
CourseTabView
):
...
@@ -113,11 +112,9 @@ class CourseHomeFragmentView(EdxFragmentView):
...
@@ -113,11 +112,9 @@ class CourseHomeFragmentView(EdxFragmentView):
# Get the handouts
# Get the handouts
handouts_html
=
get_course_info_section
(
request
,
request
.
user
,
course
,
'handouts'
)
handouts_html
=
get_course_info_section
(
request
,
request
.
user
,
course
,
'handouts'
)
# Only show the reviews button if configured
show_reviews_link
=
CourseReviewsModuleFragmentView
.
is_configured
()
# Render the course home fragment
# Render the course home fragment
context
=
{
context
=
{
'request'
:
request
,
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'course'
:
course
,
'course'
:
course
,
'course_key'
:
course_key
,
'course_key'
:
course_key
,
...
@@ -130,7 +127,6 @@ class CourseHomeFragmentView(EdxFragmentView):
...
@@ -130,7 +127,6 @@ class CourseHomeFragmentView(EdxFragmentView):
'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
,
'show_reviews_link'
:
show_reviews_link
,
}
}
html
=
render_to_string
(
'course_experience/course-home-fragment.html'
,
context
)
html
=
render_to_string
(
'course_experience/course-home-fragment.html'
,
context
)
return
Fragment
(
html
)
return
Fragment
(
html
)
openedx/features/course_experience/views/course_updates.py
View file @
e6c94400
...
@@ -53,12 +53,10 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -53,12 +53,10 @@ class CourseUpdatesFragmentView(EdxFragmentView):
course_url_name
=
default_course_url_name
(
request
)
course_url_name
=
default_course_url_name
(
request
)
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
# Fetch all of the updates individually
ordered_updates
=
self
.
get_ordered_updates
(
request
,
course
)
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
plain_html_updates
=
''
ordered_updates
=
self
.
order_updates
(
info_module
.
items
)
if
ordered_updates
:
plain_html_updates
=
self
.
get_plain_html_updates
(
request
,
course
)
# Older implementations and a few tests store a single html object representing all the updates
plain_html_updates
=
info_module
.
data
# Render the course home fragment
# Render the course home fragment
context
=
{
context
=
{
...
@@ -74,16 +72,33 @@ class CourseUpdatesFragmentView(EdxFragmentView):
...
@@ -74,16 +72,33 @@ class CourseUpdatesFragmentView(EdxFragmentView):
return
Fragment
(
html
)
return
Fragment
(
html
)
@classmethod
@classmethod
def
order_updates
(
self
,
updates
):
def
get_ordered_updates
(
self
,
request
,
course
):
"""
"""
Returns any course updates in reverse chronological order.
Returns any course updates in reverse chronological order.
"""
"""
sorted_updates
=
[
update
for
update
in
updates
if
update
.
get
(
'status'
)
==
self
.
STATUS_VISIBLE
]
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
sorted_updates
.
sort
(
updates
=
info_module
.
items
if
info_module
else
[]
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'
]),
key
=
lambda
item
:
(
self
.
safe_parse_date
(
item
[
'date'
]),
item
[
'id'
]),
reverse
=
True
reverse
=
True
)
)
return
sorted_updates
return
ordered_updates
@classmethod
def
has_updates
(
self
,
request
,
course
):
return
len
(
self
.
get_ordered_updates
(
request
,
course
))
>
0
@classmethod
def
get_plain_html_updates
(
self
,
request
,
course
):
"""
Returns any course updates in an html chunk. Used
for older implementations and a few tests that store
a single html object representing all the updates.
"""
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
return
info_module
.
data
if
info_module
else
''
@staticmethod
@staticmethod
def
safe_parse_date
(
date
):
def
safe_parse_date
(
date
):
...
...
openedx/features/course_experience/views/welcome_message.py
View file @
e6c94400
...
@@ -53,14 +53,11 @@ class WelcomeMessageFragmentView(EdxFragmentView):
...
@@ -53,14 +53,11 @@ 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.
"""
"""
info_module
=
get_course_info_section_module
(
request
,
request
.
user
,
course
,
'updates'
)
if
not
info_module
:
return
None
# Return the course update with the most recent publish date
# Return the course update with the most recent publish date
ordered_updates
=
CourseUpdatesFragmentView
.
order_updates
(
info_module
.
items
)
ordered_updates
=
CourseUpdatesFragmentView
.
get_ordered_updates
(
request
,
course
)
content
=
None
content
=
None
if
ordered_updates
:
if
ordered_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
)
content
=
info_block
.
system
.
replace_urls
(
ordered_updates
[
0
][
'content'
])
content
=
info_block
.
system
.
replace_urls
(
ordered_updates
[
0
][
'content'
])
...
...
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