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
786c4456
Commit
786c4456
authored
Nov 05, 2015
by
Peter Fogg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Last-accessed courseware on the home page.
ECOM-2806
parent
96d030b6
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
113 additions
and
48 deletions
+113
-48
common/test/acceptance/tests/lms/test_library.py
+3
-3
lms/djangoapps/courseware/features/navigation.feature
+0
-7
lms/djangoapps/courseware/features/navigation.py
+0
-6
lms/djangoapps/courseware/field_overrides.py
+8
-3
lms/djangoapps/courseware/self_paced_overrides.py
+1
-1
lms/djangoapps/courseware/tests/test_course_info.py
+29
-0
lms/djangoapps/courseware/views.py
+33
-18
lms/static/sass/base/_variables.scss
+1
-0
lms/static/sass/course/_info.scss
+28
-6
lms/static/sass/course/layout/_courseware_header.scss
+0
-1
lms/templates/courseware/info.html
+10
-3
No files found.
common/test/acceptance/tests/lms/test_library.py
View file @
786c4456
...
...
@@ -127,9 +127,9 @@ class LibraryContentTestBase(UniqueCourseTest):
Open library page in LMS
"""
self
.
courseware_page
.
visit
()
paragraphs
=
self
.
courseware_page
.
q
(
css
=
'.course-content p'
)
if
paragraphs
and
"You were most recently in"
in
paragraphs
.
text
[
0
]
:
paragraphs
[
0
]
.
find_element_by_tag_name
(
'a'
)
.
click
()
paragraphs
=
self
.
courseware_page
.
q
(
css
=
'.course-content p'
)
.
results
if
not
paragraphs
:
self
.
courseware_page
.
q
(
css
=
'.menu-item a'
)
.
results
[
0
]
.
click
()
block_id
=
block_id
if
block_id
is
not
None
else
self
.
lib_block
.
locator
#pylint: disable=attribute-defined-outside-init
self
.
library_content_page
=
LibraryContentXBlockWrapper
(
self
.
browser
,
block_id
)
...
...
lms/djangoapps/courseware/features/navigation.feature
View file @
786c4456
...
...
@@ -19,10 +19,3 @@ Feature: LMS.Navigate Course
When
I navigate to an item in a sequence
Then
I see the content of the sequence item
And
a
"seq_goto"
browser event is emitted
Scenario
:
I
can return to the last section I visited
Given
I am viewing a course with multiple sections
When
I navigate to a section
And
I see the content of the section
And
I return to the course
Then
I see that I was most recently in the subsection
lms/djangoapps/courseware/features/navigation.py
View file @
786c4456
...
...
@@ -136,12 +136,6 @@ def and_i_return_to_the_course(step):
world
.
css_click
(
course
)
@step
(
u'I see that I was most recently in the subsection'
)
def
then_i_see_that_i_was_most_recently_in_the_subsection
(
step
):
message
=
world
.
css_text
(
'section.course-content > p'
)
assert_in
(
"You were most recently in Test Subsection 2"
,
message
)
def
create_course
():
world
.
clear_courses
()
world
.
scenario_dict
[
'COURSE'
]
=
world
.
CourseFactory
.
create
(
...
...
lms/djangoapps/courseware/field_overrides.py
View file @
786c4456
...
...
@@ -228,11 +228,16 @@ class FieldOverrideProvider(object):
@abstractmethod
def
enabled_for
(
self
,
course
):
# pragma no cover
"""
Return True if this provider should be enabled for a given course
Return True if this provider should be enabled for a given course,
and False otherwise.
Return False otherwise
Concrete implementations are responsible for implementing this method.
Concrete implementations are responsible for implementing this method
Arguments:
course (CourseModule or None)
Returns:
bool
"""
return
False
...
...
lms/djangoapps/courseware/self_paced_overrides.py
View file @
786c4456
...
...
@@ -25,4 +25,4 @@ class SelfPacedDateOverrideProvider(FieldOverrideProvider):
@classmethod
def
enabled_for
(
cls
,
course
):
"""This provider is enabled for self-paced courses only."""
return
SelfPacedConfiguration
.
current
()
.
enabled
and
course
.
self_pac
ed
return
course
is
not
None
and
course
.
self_paced
and
SelfPacedConfiguration
.
current
()
.
enabl
ed
lms/djangoapps/courseware/tests/test_course_info.py
View file @
786c4456
...
...
@@ -11,6 +11,7 @@ from django.core.urlresolvers import reverse
from
django.test.utils
import
override_settings
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
openedx.core.djangoapps.self_paced.models
import
SelfPacedConfiguration
from
util.date_utils
import
strftime_localized
from
xmodule.modulestore.tests.django_utils
import
(
ModuleStoreTestCase
,
...
...
@@ -92,6 +93,33 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_last_accessed_courseware_not_shown
(
self
):
SelfPacedConfiguration
(
enable_course_home_improvements
=
True
)
.
save
()
url
=
reverse
(
'info'
,
args
=
(
unicode
(
self
.
course
.
id
),))
response
=
self
.
client
.
get
(
url
)
self
.
assertNotIn
(
'Jump back to where you were last:'
,
response
.
content
)
def
test_last_accessed_shown
(
self
):
SelfPacedConfiguration
(
enable_course_home_improvements
=
True
)
.
save
()
chapter
=
ItemFactory
.
create
(
category
=
"chapter"
,
parent_location
=
self
.
course
.
location
)
section
=
ItemFactory
.
create
(
category
=
'section'
,
parent_location
=
chapter
.
location
)
section_url
=
reverse
(
'courseware_section'
,
kwargs
=
{
'section'
:
section
.
url_name
,
'chapter'
:
chapter
.
url_name
,
'course_id'
:
self
.
course
.
id
}
)
self
.
client
.
get
(
section_url
)
info_url
=
reverse
(
'info'
,
args
=
(
unicode
(
self
.
course
.
id
),))
info_page_response
=
self
.
client
.
get
(
info_url
)
self
.
assertIn
(
'Jump back to where you were last:'
,
info_page_response
.
content
)
class
CourseInfoTestCaseCCX
(
SharedModuleStoreTestCase
,
LoginEnrollmentTestCase
):
"""
...
...
@@ -169,6 +197,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
"""
def
setUp
(
self
):
SelfPacedConfiguration
(
enabled
=
True
)
.
save
()
super
(
SelfPacedCourseInfoTestCase
,
self
)
.
setUp
()
self
.
instructor_paced_course
=
CourseFactory
.
create
(
self_paced
=
False
)
self
.
self_paced_course
=
CourseFactory
.
create
(
self_paced
=
True
)
...
...
lms/djangoapps/courseware/views.py
View file @
786c4456
...
...
@@ -72,6 +72,7 @@ from openedx.core.djangoapps.credit.api import (
)
from
shoppingcart.models
import
CourseRegistrationCode
from
shoppingcart.utils
import
is_shopping_cart_enabled
from
openedx.core.djangoapps.self_paced.models
import
SelfPacedConfiguration
from
student.models
import
UserTestGroup
,
CourseEnrollment
from
student.views
import
is_course_blocked
from
util.cache
import
cache
,
cache_if_anonymous
...
...
@@ -549,8 +550,6 @@ def _index_bulk_op(request, course_key, chapter, section, position):
context
[
'fragment'
]
=
section_module
.
render
(
STUDENT_VIEW
,
section_render_context
)
context
[
'section_title'
]
=
section_descriptor
.
display_name_with_default_escaped
else
:
# section is none, so display a message
studio_url
=
get_studio_url
(
course
,
'course'
)
prev_section
=
get_current_child
(
chapter_module
)
if
prev_section
is
None
:
# Something went wrong -- perhaps this chapter has no sections visible to the user.
...
...
@@ -559,22 +558,6 @@ def _index_bulk_op(request, course_key, chapter, section, position):
course_module
.
position
=
None
course_module
.
save
()
return
redirect
(
reverse
(
'courseware'
,
args
=
[
course
.
id
.
to_deprecated_string
()]))
prev_section_url
=
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
course_key
.
to_deprecated_string
(),
'chapter'
:
chapter_descriptor
.
url_name
,
'section'
:
prev_section
.
url_name
})
context
[
'fragment'
]
=
Fragment
(
content
=
render_to_string
(
'courseware/welcome-back.html'
,
{
'course'
:
course
,
'studio_url'
:
studio_url
,
'chapter_module'
:
chapter_module
,
'prev_section'
:
prev_section
,
'prev_section_url'
:
prev_section_url
}
))
result
=
render_to_response
(
'courseware/courseware.html'
,
context
)
except
Exception
as
e
:
...
...
@@ -729,6 +712,14 @@ def course_info(request, course_id):
'url_to_enroll'
:
url_to_enroll
,
}
# Get the URL of the user's last position in order to display the 'where you were last' message
context
[
'last_accessed_courseware'
]
=
None
if
SelfPacedConfiguration
.
current
()
.
enable_course_home_improvements
:
(
section_module
,
section_url
)
=
get_last_accessed_courseware
(
course
,
request
)
if
section_module
is
not
None
and
section_url
is
not
None
:
context
[
'last_accessed_courseware'
]
=
section_module
context
[
'last_accessed_url'
]
=
section_url
now
=
datetime
.
now
(
UTC
())
effective_start
=
_adjust_start_date_for_beta_testers
(
user
,
course
,
course_key
)
if
not
in_preview_mode
()
and
staff_access
and
now
<
effective_start
:
...
...
@@ -739,6 +730,30 @@ def course_info(request, course_id):
return
render_to_response
(
'courseware/info.html'
,
context
)
def
get_last_accessed_courseware
(
course
,
request
):
"""
Return a pair of the last-accessed courseware for this request's
user, and a URL for that module.
"""
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
course
.
id
,
request
.
user
,
course
,
depth
=
2
)
course_module
=
get_module_for_descriptor
(
request
.
user
,
request
,
course
,
field_data_cache
,
course
.
id
,
course
=
course
)
chapter_module
=
get_current_child
(
course_module
)
if
chapter_module
is
not
None
:
section_module
=
get_current_child
(
chapter_module
)
if
section_module
is
not
None
:
url
=
reverse
(
'courseware_section'
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
),
'chapter'
:
chapter_module
.
url_name
,
'section'
:
section_module
.
url_name
})
return
(
section_module
,
url
)
return
(
None
,
None
)
@ensure_csrf_cookie
@ensure_valid_course_key
def
static_tab
(
request
,
course_id
,
tab_slug
):
...
...
lms/static/sass/base/_variables.scss
View file @
786c4456
...
...
@@ -465,6 +465,7 @@ $courseware-navigation-color: $blue !default;
$homepage__header--gradient__color--alpha
:
lighten
(
$gray
,
15%
)
!
default
;
$homepage__header--gradient__color--bravo
:
saturate
(
$gray
,
30%
)
!
default
;
$homepage__header--background
:
lighten
(
$gray
,
15%
)
!
default
;
$homepage-background
:
rgb
(
252
,
252
,
252
);
$course-card-height
:
(
$baseline
*
18
)
!
default
;
$course-image-height
:
(
$baseline
*
8
)
!
default
;
$course-info-height
:
(
$baseline
*
10
)
!
default
;
...
...
lms/static/sass/course/_info.scss
View file @
786c4456
.home-wrapper
{
max-width
:
1180px
;
.home
{
@include
clearfix
();
max-width
:
1140px
;
margin
:
0
auto
;
padding
:
$baseline
$baseline
(
$baseline
/
2
)
$baseline
;
.home
{
margin
:
$baseline
;
.page-header-main
{
display
:
inline-block
;
width
:
flex-grid
(
8
,
12
);
margin
:
0
;
.page-title
{
margin-bottom
:
5px
;
...
...
@@ -17,11 +21,29 @@
text-transform
:
none
;
}
}
.page-header-secondary
{
display
:
inline-block
;
width
:
flex-grid
(
4
,
12
);
margin
:
0
;
padding
:
(
$baseline
/
2
)
(
$baseline
*
0
.75
);
border
:
1px
solid
$blue
;
background-color
:
$homepage-background
;
@extend
%t-title8
;
color
:
$blue-d1
;
@extend
%cont-truncated
;
vertical-align
:
text-bottom
;
.last-accessed-message
{
display
:
inline-block
;
@include
margin-left
(
$baseline
*
0
.75
);
}
}
}
div
.info-wrapper
{
background-color
:
rgb
(
252
,
252
,
252
)
;
background-color
:
$homepage-background
;
section
.updates
{
@extend
.content
;
...
...
@@ -63,7 +85,7 @@ div.info-wrapper {
margin-bottom
:
(
$baseline
/
4
);
text-transform
:
none
;
background
:
url('
#{
$static-path
}
/images/calendar-icon.png')
0
center
no-repeat
;
padding-left
:
$baseline
;
@include
padding-left
(
$baseline
)
;
}
section
.update-description
{
...
...
lms/static/sass/course/layout/_courseware_header.scss
View file @
786c4456
...
...
@@ -22,7 +22,6 @@
list-style
:
none
;
&
.prominent
{
margin-right
:
16px
;
@include
margin-right
(
16px
);
background
:
rgba
(
255
,
255
,
255
,
0
.5
);
border-radius
:
3px
;
...
...
lms/templates/courseware/info.html
View file @
786c4456
...
...
@@ -45,11 +45,18 @@ from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
<
%
block
name=
"bodyclass"
>
view-in-course view-course-info ${course.css_class or ''}
</
%
block>
<section
class=
"container"
>
<div
class=
"home
-wrapper
"
>
<
section
class=
"home
"
>
<div
class=
"home"
>
<
div
class=
"page-header-main
"
>
<h1
class=
"page-title"
>
${_("Welcome to {org}'s {course_name}!").format(org=course.id.org, course_name=course.id.course) | h}
</h1>
<h2
class=
"page-subtitle"
>
${course.display_name | h}
</h2>
</section>
</div>
% if last_accessed_courseware:
<div
class=
"page-header-secondary"
>
<i
class=
"fa fa-clock-o"
></i>
<p
class=
"last-accessed-message"
>
${_("Jump back to where you were last:")}
</p>
<a
href=
"${last_accessed_url}"
>
${last_accessed_courseware.display_name | h}
</a>
</div>
% endif
</div>
<div
class=
"info-wrapper"
>
% if user.is_authenticated():
...
...
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