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
482f7652
Commit
482f7652
authored
May 10, 2017
by
Andy Armstrong
Committed by
GitHub
May 10, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15064 from edx/andya/welcome-message
Show a welcome message on the course home page
parents
544d5d59
64de4432
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
291 additions
and
46 deletions
+291
-46
common/lib/xmodule/xmodule/html_module.py
+12
-6
lms/djangoapps/courseware/courses.py
+8
-1
lms/djangoapps/courseware/tabs.py
+2
-2
lms/djangoapps/courseware/views/views.py
+3
-3
lms/static/sass/features/_course-experience.scss
+14
-0
openedx/core/djangoapps/plugin_api/views.py
+7
-3
openedx/features/course_bookmarks/views/course_bookmarks.py
+2
-2
openedx/features/course_experience/__init__.py
+1
-1
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
+6
-0
openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html
+14
-0
openedx/features/course_experience/tests/views/test_course_home.py
+26
-5
openedx/features/course_experience/tests/views/test_course_updates.py
+60
-20
openedx/features/course_experience/tests/views/test_welcome_message.py
+72
-0
openedx/features/course_experience/urls.py
+6
-0
openedx/features/course_experience/views/course_home.py
+7
-0
openedx/features/course_experience/views/course_updates.py
+2
-2
openedx/features/course_experience/views/welcome_message.py
+48
-0
requirements/edx/base.txt
+1
-1
No files found.
common/lib/xmodule/xmodule/html_module.py
View file @
482f7652
...
...
@@ -446,18 +446,24 @@ class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
return
self
.
data
.
replace
(
"
%%
USER_ID
%%
"
,
self
.
system
.
anonymous_student_id
)
return
self
.
data
else
:
course_updates
=
[
item
for
item
in
self
.
items
if
item
.
get
(
'status'
)
==
self
.
STATUS_VISIBLE
]
course_updates
.
sort
(
key
=
lambda
item
:
(
CourseInfoModule
.
safe_parse_date
(
item
[
'date'
]),
item
[
'id'
]),
reverse
=
True
)
course_updates
=
self
.
ordered_updates
()
context
=
{
'visible_updates'
:
course_updates
[:
3
],
'hidden_updates'
:
course_updates
[
3
:],
}
return
self
.
system
.
render_template
(
"{0}/course_updates.html"
.
format
(
self
.
TEMPLATE_DIR
),
context
)
def
ordered_updates
(
self
):
"""
Returns any course updates in reverse chronological order.
"""
course_updates
=
[
item
for
item
in
self
.
items
if
item
.
get
(
'status'
)
==
self
.
STATUS_VISIBLE
]
course_updates
.
sort
(
key
=
lambda
item
:
(
CourseInfoModule
.
safe_parse_date
(
item
[
'date'
]),
item
[
'id'
]),
reverse
=
True
)
return
course_updates
@staticmethod
def
safe_parse_date
(
date
):
"""
...
...
lms/djangoapps/courseware/courses.py
View file @
482f7652
...
...
@@ -235,6 +235,13 @@ def get_course_about_section(request, course, section_key):
raise
KeyError
(
"Invalid about key "
+
str
(
section_key
))
def
get_course_info_usage_key
(
course
,
section_key
):
"""
Returns the usage key for the specified section's course info module.
"""
return
course
.
id
.
make_usage_key
(
'course_info'
,
section_key
)
def
get_course_info_section_module
(
request
,
user
,
course
,
section_key
):
"""
This returns the course info module for a given section_key.
...
...
@@ -245,7 +252,7 @@ def get_course_info_section_module(request, user, course, section_key):
- updates
- guest_updates
"""
usage_key
=
course
.
id
.
make_usage_key
(
'course_info'
,
section_key
)
usage_key
=
get_course_info_usage_key
(
course
,
section_key
)
# Use an empty cache
field_data_cache
=
FieldDataCache
([],
course
.
id
,
user
)
...
...
lms/djangoapps/courseware/tabs.py
View file @
482f7652
...
...
@@ -10,7 +10,7 @@ from django.utils.translation import ugettext as _, ugettext_noop
from
courseware.access
import
has_access
from
courseware.entrance_exams
import
user_can_skip_entrance_exam
from
openedx.core.lib.course_tabs
import
CourseTabPluginManager
from
openedx.features.course_experience
import
defaut_course_url_name
,
UNIFIED_COURSE_EXPERIENCE_FLAG
from
openedx.features.course_experience
import
defau
l
t_course_url_name
,
UNIFIED_COURSE_EXPERIENCE_FLAG
from
request_cache.middleware
import
RequestCache
from
student.models
import
CourseEnrollment
from
xmodule.tabs
import
CourseTab
,
CourseTabList
,
key_checker
,
link_reverse_func
...
...
@@ -45,7 +45,7 @@ class CoursewareTab(EnrolledTab):
Returns a function that computes the URL for this tab.
"""
request
=
RequestCache
.
get_current_request
()
url_name
=
defaut_course_url_name
(
request
)
url_name
=
defau
l
t_course_url_name
(
request
)
return
link_reverse_func
(
url_name
)
...
...
lms/djangoapps/courseware/views/views.py
View file @
482f7652
...
...
@@ -428,7 +428,7 @@ class StaticCourseTabView(EdxFragmentView):
"""
return
get_static_tab_fragment
(
request
,
course
,
tab
)
def
render_
to_standalone_html
(
self
,
request
,
fragment
,
course
=
None
,
tab
=
None
,
**
kwargs
):
def
render_
standalone_response
(
self
,
request
,
fragment
,
course
=
None
,
tab
=
None
,
**
kwargs
):
"""
Renders this static tab's fragment to HTML for a standalone page.
"""
...
...
@@ -531,14 +531,14 @@ class CourseTabView(EdxFragmentView):
tab
=
page_context
[
'tab'
]
return
tab
.
render_to_fragment
(
request
,
course
,
**
kwargs
)
def
render_
to_standalone_html
(
self
,
request
,
fragment
,
course
=
None
,
tab
=
None
,
page_context
=
None
,
**
kwargs
):
def
render_
standalone_response
(
self
,
request
,
fragment
,
course
=
None
,
tab
=
None
,
page_context
=
None
,
**
kwargs
):
"""
Renders this course tab's fragment to HTML for a standalone page.
"""
if
not
page_context
:
page_context
=
self
.
create_page_context
(
request
,
course
=
course
,
tab
=
tab
,
**
kwargs
)
page_context
[
'fragment'
]
=
fragment
return
render_to_
string
(
'courseware/tab-view.html'
,
page_context
)
return
render_to_
response
(
'courseware/tab-view.html'
,
page_context
)
@ensure_csrf_cookie
...
...
lms/static/sass/features/_course-experience.scss
View file @
482f7652
// Welcome message
.welcome-message
{
border
:
solid
1px
$lms-border-color
;
@include
border-left
(
solid
4px
$black
);
margin-bottom
:
$baseline
;
padding
:
$baseline
;
h1
,
h2
,
h3
{
font-size
:
font-size
(
large
);
font-weight
:
bold
;
color
:
$black
;
}
}
// Course sidebar
.course-sidebar
{
@include
margin-left
(
0
);
...
...
openedx/core/djangoapps/plugin_api/views.py
View file @
482f7652
...
...
@@ -2,11 +2,11 @@
Views for building plugins.
"""
from
abc
import
abstractmethod
import
logging
from
django.conf
import
settings
from
django.contrib.staticfiles.storage
import
staticfiles_storage
from
django.http
import
HttpResponse
from
django.shortcuts
import
render_to_response
from
web_fragments.views
import
FragmentView
...
...
@@ -78,10 +78,14 @@ class EdxFragmentView(FragmentView):
for
js_file
in
self
.
js_dependencies
():
fragment
.
add_javascript_url
(
staticfiles_storage
.
url
(
js_file
))
def
render_
to_standalone_html
(
self
,
request
,
fragment
,
**
kwargs
):
def
render_
standalone_response
(
self
,
request
,
fragment
,
**
kwargs
):
"""
Renders this fragment to HTML for a standalone page.
Renders a standalone page for the specified fragment.
Note: if fragment is None, a 204 response will be returned (no content).
"""
if
fragment
is
None
:
return
HttpResponse
(
status
=
204
)
context
=
{
'uses-pattern-library'
:
self
.
USES_PATTERN_LIBRARY
,
'settings'
:
settings
,
...
...
openedx/features/course_bookmarks/views/course_bookmarks.py
View file @
482f7652
...
...
@@ -15,7 +15,7 @@ from django.views.generic import View
from
courseware.courses
import
get_course_with_access
from
opaque_keys.edx.keys
import
CourseKey
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.features.course_experience
import
defaut_course_url_name
from
openedx.features.course_experience
import
defau
l
t_course_url_name
from
util.views
import
ensure_valid_course_key
from
web_fragments.fragment
import
Fragment
...
...
@@ -38,7 +38,7 @@ class CourseBookmarksView(View):
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
course_url_name
=
defaut_course_url_name
(
request
)
course_url_name
=
defau
l
t_course_url_name
(
request
)
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
# Render the bookmarks list as a fragment
...
...
openedx/features/course_experience/__init__.py
View file @
482f7652
...
...
@@ -14,7 +14,7 @@ UNIFIED_COURSE_EXPERIENCE_FLAG = 'unified_course_experience'
UNIFIED_COURSE_VIEW_FLAG
=
'unified_course_view'
def
defaut_course_url_name
(
request
=
None
):
def
defau
l
t_course_url_name
(
request
=
None
):
"""
Returns the default course URL name for the current user.
"""
...
...
openedx/features/course_experience/templates/course_experience/course-home-fragment.html
View file @
482f7652
...
...
@@ -58,6 +58,12 @@ from openedx.features.course_experience import UNIFIED_COURSE_EXPERIENCE_FLAG
<div
class=
"page-content"
>
<div
class=
"layout layout-1q3q"
>
<main
class=
"layout-col layout-col-b"
>
% if welcome_message_fragment and waffle.flag_is_active(request, UNIFIED_COURSE_EXPERIENCE_FLAG):
<div
class=
"section section-dates"
>
${HTML(welcome_message_fragment.body_html())}
</div>
% endif
${HTML(outline_fragment.body_html())}
</main>
<aside
class=
"course-sidebar layout-col layout-col-a"
>
...
...
openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html
0 → 100644
View file @
482f7652
## mako
<
%
page
expression_filter=
"h"
/>
<
%
namespace
name=
'static'
file=
'../static_content.html'
/>
<
%!
from
openedx
.
core
.
djangolib
.
markup
import
HTML
%
>
<
%
block
name=
"content"
>
<div
class=
"welcome-message"
>
${HTML(welcome_message_html)}
</div>
</
%
block>
openedx/features/course_experience/tests/views/test_course_home.py
View file @
482f7652
...
...
@@ -6,7 +6,6 @@ from waffle.testutils import override_flag
from
django.core.urlresolvers
import
reverse
from
openedx.core.djangoapps.content.block_structure.api
import
get_course_in_cache
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
...
...
@@ -15,7 +14,10 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec
from
openedx.features.course_experience
import
UNIFIED_COURSE_EXPERIENCE_FLAG
from
.test_course_updates
import
create_course_update
,
remove_course_updates
TEST_PASSWORD
=
'test'
TEST_WELCOME_MESSAGE
=
'<h2>Welcome!</h2>'
def
course_home_url
(
course
):
...
...
@@ -55,6 +57,9 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
# Create a welcome message
create_course_update
(
cls
.
course
,
cls
.
user
,
TEST_WELCOME_MESSAGE
)
def
setUp
(
self
):
"""
Set up for the tests.
...
...
@@ -62,6 +67,10 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
super
(
TestCourseHomePage
,
self
)
.
setUp
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
super
(
TestCourseHomePage
,
self
)
.
tearDown
()
@override_flag
(
UNIFIED_COURSE_EXPERIENCE_FLAG
,
active
=
True
)
def
test_unified_page
(
self
):
"""
...
...
@@ -71,15 +80,27 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
response
=
self
.
client
.
get
(
url
)
self
.
assertContains
(
response
,
'<h2 class="hd hd-3 page-title">Test Course</h2>'
)
@override_flag
(
UNIFIED_COURSE_EXPERIENCE_FLAG
,
active
=
True
)
def
test_welcome_message_when_unified
(
self
):
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
self
.
assertContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
@override_flag
(
UNIFIED_COURSE_EXPERIENCE_FLAG
,
active
=
False
)
def
test_welcome_message_when_not_unified
(
self
):
url
=
course_home_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
self
.
assertNotContains
(
response
,
TEST_WELCOME_MESSAGE
,
status_code
=
200
)
def
test_queries
(
self
):
"""
Verify that the view's query count doesn't regress.
"""
# Pre-f
ill the course blocks cache
get_course_in_cache
(
self
.
course
.
id
)
# Pre-f
etch the view to populate any caches
course_home_url
(
self
.
course
)
# Fetch the view and verify the query counts
with
self
.
assertNumQueries
(
35
):
with
check_mongo_calls
(
3
):
with
self
.
assertNumQueries
(
43
):
with
check_mongo_calls
(
5
):
url
=
course_home_url
(
self
.
course
)
self
.
client
.
get
(
url
)
openedx/features/course_experience/tests/views/test_course_updates.py
View file @
482f7652
...
...
@@ -3,11 +3,13 @@ Tests for the course updates page.
"""
from
django.core.urlresolvers
import
reverse
from
courseware.courses
import
get_course_info_section_module
,
get_course_info_usage_key
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
xmodule.html_module
import
CourseInfoModule
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
,
check_mongo_calls
...
...
@@ -26,6 +28,51 @@ def course_updates_url(course):
)
def
create_course_update
(
course
,
user
,
content
,
date
=
'December 31, 1999'
):
"""
Creates a test welcome message for the specified course.
"""
updates_usage_key
=
get_course_info_usage_key
(
course
,
'updates'
)
try
:
course_updates
=
modulestore
()
.
get_item
(
updates_usage_key
)
except
ItemNotFoundError
:
course_updates
=
create_course_updates_block
(
course
,
user
)
course_updates
.
items
.
append
({
"id"
:
len
(
course_updates
.
items
)
+
1
,
"date"
:
date
,
"content"
:
content
,
"status"
:
CourseInfoModule
.
STATUS_VISIBLE
})
modulestore
()
.
update_item
(
course_updates
,
user
.
id
)
def
create_course_updates_block
(
course
,
user
):
"""
Create a course updates block.
"""
updates_usage_key
=
get_course_info_usage_key
(
course
,
'updates'
)
course_updates
=
modulestore
()
.
create_item
(
user
.
id
,
updates_usage_key
.
course_key
,
updates_usage_key
.
block_type
,
block_id
=
updates_usage_key
.
block_id
)
course_updates
.
data
=
''
return
course_updates
def
remove_course_updates
(
course
):
"""
Remove any course updates in the specified course.
"""
updates_usage_key
=
get_course_info_usage_key
(
course
,
'updates'
)
try
:
course_updates
=
modulestore
()
.
get_item
(
updates_usage_key
)
course_updates
.
items
=
[]
except
ItemNotFoundError
:
pass
class
TestCourseUpdatesPage
(
SharedModuleStoreTestCase
):
"""
Test the course updates page.
...
...
@@ -50,24 +97,6 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
# Create course updates
cls
.
create_course_updates
(
cls
.
course
,
cls
.
user
)
@classmethod
def
create_course_updates
(
cls
,
course
,
user
,
count
=
5
):
"""
Create some test course updates.
"""
updates_usage_key
=
course
.
id
.
make_usage_key
(
'course_info'
,
'updates'
)
course_updates
=
modulestore
()
.
create_item
(
user
.
id
,
updates_usage_key
.
course_key
,
updates_usage_key
.
block_type
,
block_id
=
updates_usage_key
.
block_id
)
course_updates
.
data
=
u'<ol><li><a href="test">Test Update</a></li></ol>'
modulestore
()
.
update_item
(
course_updates
,
user
.
id
)
def
setUp
(
self
):
"""
Set up for the tests.
...
...
@@ -75,14 +104,25 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
super
(
TestCourseUpdatesPage
,
self
)
.
setUp
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
super
(
TestCourseUpdatesPage
,
self
)
.
tearDown
()
def
test_view
(
self
):
create_course_update
(
self
.
course
,
self
.
user
,
'First Message'
)
create_course_update
(
self
.
course
,
self
.
user
,
'Second Message'
)
url
=
course_updates_url
(
self
.
course
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_content
=
response
.
content
.
decode
(
"utf-8"
)
self
.
assert
In
(
'<a href="test">Test Update</a>'
,
response_content
)
self
.
assertContains
(
response
,
'First Message'
)
self
.
assert
Contains
(
response
,
'Second Message'
)
def
test_queries
(
self
):
create_course_update
(
self
.
course
,
self
.
user
,
'First Message'
)
# Pre-fetch the view to populate any caches
course_updates_url
(
self
.
course
)
# Fetch the view and verify that the query counts haven't changed
with
self
.
assertNumQueries
(
32
):
with
check_mongo_calls
(
4
):
...
...
openedx/features/course_experience/tests/views/test_welcome_message.py
0 → 100644
View file @
482f7652
"""
Tests for course welcome messages.
"""
from
django.core.urlresolvers
import
reverse
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
.test_course_updates
import
create_course_update
,
remove_course_updates
TEST_PASSWORD
=
'test'
TEST_WELCOME_MESSAGE
=
'<h2>Welcome!</h2>'
def
welcome_message_url
(
course
):
"""
Returns the URL for the welcome message view.
"""
return
reverse
(
'openedx.course_experience.welcome_message_fragment_view'
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
),
}
)
class
TestWelcomeMessageView
(
SharedModuleStoreTestCase
):
"""
Tests for the course welcome message fragment view.
"""
@classmethod
def
setUpClass
(
cls
):
"""Set up the simplest course possible."""
# setUpClassAndTestData() already calls setUpClass on SharedModuleStoreTestCase
# pylint: disable=super-method-not-called
with
super
(
TestWelcomeMessageView
,
cls
)
.
setUpClassAndTestData
():
with
cls
.
store
.
default_store
(
ModuleStoreEnum
.
Type
.
split
):
cls
.
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
cls
.
course
.
id
):
# Create a basic course structure
chapter
=
ItemFactory
.
create
(
category
=
'chapter'
,
parent_location
=
cls
.
course
.
location
)
section
=
ItemFactory
.
create
(
category
=
'sequential'
,
parent_location
=
chapter
.
location
)
ItemFactory
.
create
(
category
=
'vertical'
,
parent_location
=
section
.
location
)
@classmethod
def
setUpTestData
(
cls
):
"""Set up and enroll our fake user in the course."""
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
def
setUp
(
self
):
super
(
TestWelcomeMessageView
,
self
)
.
setUp
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
tearDown
(
self
):
remove_course_updates
(
self
.
course
)
super
(
TestWelcomeMessageView
,
self
)
.
tearDown
()
def
test_welcome_message
(
self
):
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
,
'Retroactive Update'
,
date
=
'January 1, 2010'
)
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertContains
(
response
,
'Second Update'
)
def
test_empty_welcome_message
(
self
):
response
=
self
.
client
.
get
(
welcome_message_url
(
self
.
course
))
self
.
assertEqual
(
response
.
status_code
,
204
)
openedx/features/course_experience/urls.py
View file @
482f7652
...
...
@@ -7,6 +7,7 @@ from django.conf.urls import url
from
views.course_home
import
CourseHomeView
,
CourseHomeFragmentView
from
views.course_outline
import
CourseOutlineFragmentView
from
views.course_updates
import
CourseUpdatesFragmentView
,
CourseUpdatesView
from
views.welcome_message
import
WelcomeMessageFragmentView
urlpatterns
=
[
url
(
...
...
@@ -34,4 +35,9 @@ urlpatterns = [
CourseUpdatesFragmentView
.
as_view
(),
name
=
'openedx.course_experience.course_updates_fragment_view'
,
),
url
(
r'^welcome_message_fragment$'
,
WelcomeMessageFragmentView
.
as_view
(),
name
=
'openedx.course_experience.welcome_message_fragment_view'
,
),
]
openedx/features/course_experience/views/course_home.py
View file @
482f7652
...
...
@@ -18,6 +18,7 @@ from web_fragments.fragment import Fragment
from
.course_outline
import
CourseOutlineFragmentView
from
.course_dates
import
CourseDatesFragmentView
from
.welcome_message
import
WelcomeMessageFragmentView
from
..utils
import
get_course_outline_block_tree
...
...
@@ -93,6 +94,11 @@ class CourseHomeFragmentView(EdxFragmentView):
# Get resume course information
has_visited_course
,
resume_course_url
=
self
.
_get_resume_course_info
(
request
,
course_id
)
# Render the welcome message as a fragment
welcome_message_fragment
=
WelcomeMessageFragmentView
()
.
render_to_fragment
(
request
,
course_id
=
course_id
,
**
kwargs
)
# Render the course dates as a fragment
dates_fragment
=
CourseDatesFragmentView
()
.
render_to_fragment
(
request
,
course_id
=
course_id
,
**
kwargs
)
...
...
@@ -113,6 +119,7 @@ class CourseHomeFragmentView(EdxFragmentView):
'has_visited_course'
:
has_visited_course
,
'resume_course_url'
:
resume_course_url
,
'dates_fragment'
:
dates_fragment
,
'welcome_message_fragment'
:
welcome_message_fragment
,
'disable_courseware_js'
:
True
,
'uses_pattern_library'
:
True
,
}
...
...
openedx/features/course_experience/views/course_updates.py
View file @
482f7652
...
...
@@ -13,7 +13,7 @@ from courseware.courses import get_course_info_section, get_course_with_access
from
lms.djangoapps.courseware.views.views
import
CourseTabView
from
opaque_keys.edx.keys
import
CourseKey
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
openedx.features.course_experience
import
defaut_course_url_name
from
openedx.features.course_experience
import
defau
l
t_course_url_name
from
web_fragments.fragment
import
Fragment
...
...
@@ -45,7 +45,7 @@ class CourseUpdatesFragmentView(EdxFragmentView):
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
course_url_name
=
defaut_course_url_name
(
request
)
course_url_name
=
defau
l
t_course_url_name
(
request
)
course_url
=
reverse
(
course_url_name
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)})
# Fetch the updates as HTML
...
...
openedx/features/course_experience/views/welcome_message.py
0 → 100644
View file @
482f7652
"""
View logic for handling course welcome messages.
"""
from
django.template.loader
import
render_to_string
from
courseware.courses
import
get_course_info_section_module
,
get_course_with_access
from
opaque_keys.edx.keys
import
CourseKey
from
openedx.core.djangoapps.plugin_api.views
import
EdxFragmentView
from
web_fragments.fragment
import
Fragment
class
WelcomeMessageFragmentView
(
EdxFragmentView
):
"""
A fragment that displays a course's welcome message.
"""
def
render_to_fragment
(
self
,
request
,
course_id
=
None
,
**
kwargs
):
"""
Renders the welcome message fragment for the specified course.
Returns: A fragment, or None if there is no welcome message.
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
welcome_message_html
=
self
.
welcome_message_html
(
request
,
course
)
if
not
welcome_message_html
:
return
None
context
=
{
'welcome_message_html'
:
welcome_message_html
,
}
html
=
render_to_string
(
'course_experience/welcome-message-fragment.html'
,
context
)
return
Fragment
(
html
)
@classmethod
def
welcome_message_html
(
cls
,
request
,
course
):
"""
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
info_block
=
getattr
(
info_module
,
'_xmodule'
,
info_module
)
ordered_updates
=
info_block
.
ordered_updates
()
return
ordered_updates
[
0
][
'content'
]
if
ordered_updates
else
None
requirements/edx/base.txt
View file @
482f7652
...
...
@@ -210,7 +210,7 @@ py2neo==3.1.2
-r coverage.txt
# Support for plugins
web-fragments==0.2.
1
web-fragments==0.2.
2
xblock==0.5.0
# Third Party XBlocks
...
...
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