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
550e805b
Commit
550e805b
authored
Jan 18, 2013
by
Chris Dodge
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature/cdodge/cms-master-merge4
Conflicts: common/lib/xmodule/xmodule/course_module.py
parents
39101c76
bdc55d36
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
125 additions
and
55 deletions
+125
-55
common/djangoapps/student/views.py
+2
-5
common/lib/xmodule/xmodule/course_module.py
+49
-17
common/lib/xmodule/xmodule/tests/test_course_module.py
+52
-23
lms/djangoapps/courseware/courses.py
+16
-0
lms/djangoapps/courseware/views.py
+5
-10
lms/djangoapps/instructor/views.py
+1
-0
No files found.
common/djangoapps/student/views.py
View file @
550e805b
...
...
@@ -42,7 +42,7 @@ from xmodule.modulestore.django import modulestore
#from datetime import date
from
collections
import
namedtuple
from
courseware.courses
import
get_courses
from
courseware.courses
import
get_courses
,
sort_by_announcement
from
courseware.access
import
has_access
from
statsd
import
statsd
...
...
@@ -78,10 +78,7 @@ def index(request, extra_context={}, user=None):
domain
=
request
.
META
.
get
(
'HTTP_HOST'
)
courses
=
get_courses
(
None
,
domain
=
domain
)
# Sort courses by how far are they from they start day
key
=
lambda
course
:
course
.
days_until_start
courses
=
sorted
(
courses
,
key
=
key
,
reverse
=
True
)
courses
=
sort_by_announcement
(
courses
)
# Get the 3 most recent news
top_news
=
_get_news
(
top
=
3
)
...
...
common/lib/xmodule/xmodule/course_module.py
View file @
550e805b
import
logging
from
cStringIO
import
StringIO
from
math
import
exp
,
erf
from
lxml
import
etree
from
path
import
path
# NOTE (THK): Only used for detecting presence of syllabus
import
requests
...
...
@@ -361,35 +362,66 @@ class CourseDescriptor(SequenceDescriptor):
@property
def
is_new
(
self
):
# The course is "new" if either if the metadata flag is_new is
# true or if the course has not started yet
"""
Returns if the course has been flagged as new in the metadata. If
there is no flag, return a heuristic value considering the
announcement and the start dates.
"""
flag
=
self
.
metadata
.
get
(
'is_new'
,
None
)
if
flag
is
None
:
return
self
.
days_until_start
>
1
# Use a heuristic if the course has not been flagged
announcement
,
start
,
now
=
self
.
_sorting_dates
()
if
announcement
and
(
now
-
announcement
)
.
days
<
30
:
# The course has been announced for less that month
return
True
elif
(
now
-
start
)
.
days
<
1
:
# The course has not started yet
return
True
else
:
return
False
elif
isinstance
(
flag
,
basestring
):
return
flag
.
lower
()
in
[
'true'
,
'yes'
,
'y'
]
else
:
return
bool
(
flag
)
@property
def
days_until_start
(
self
):
def
convert_to_datetime
(
timestamp
):
def
sorting_score
(
self
):
"""
Returns a number that can be used to sort the courses according
the how "new"" they are. The "newness"" score is computed using a
heuristic that takes into account the announcement and
(advertized) start dates of the course if available.
The lower the number the "newer" the course.
"""
# Make courses that have an announcement date shave a lower
# score than courses than don't, older courses should have a
# higher score.
announcement
,
start
,
now
=
self
.
_sorting_dates
()
scale
=
300.0
# about a year
if
announcement
:
days
=
(
now
-
announcement
)
.
days
score
=
-
exp
(
-
days
/
scale
)
else
:
days
=
(
now
-
start
)
.
days
score
=
exp
(
days
/
scale
)
return
score
def
_sorting_dates
(
self
):
# utility function to get datetime objects for dates used to
# compute the is_new flag and the sorting_score
def
to_datetime
(
timestamp
):
return
datetime
.
fromtimestamp
(
time
.
mktime
(
timestamp
))
start_date
=
convert_to_datetime
(
self
.
start
)
def
get_date
(
field
):
timetuple
=
self
.
_try_parse_time
(
field
)
return
to_datetime
(
timetuple
)
if
timetuple
else
None
# Try to use course advertised date if we can parse it
advertised_start
=
self
.
metadata
.
get
(
'advertised_start'
,
None
)
if
advertised_start
:
try
:
start_date
=
datetime
.
strptime
(
advertised_start
,
"
%
Y-
%
m-
%
dT
%
H:
%
M"
)
except
ValueError
:
pass
# Invalid date, keep using 'start''
announcement
=
get_date
(
'announcement'
)
start
=
get_date
(
'advertised_start'
)
or
to_datetime
(
self
.
start
)
now
=
to_datetime
(
time
.
gmtime
())
now
=
convert_to_datetime
(
time
.
gmtime
())
days_until_start
=
(
start_date
-
now
)
.
days
return
days_until_start
return
announcement
,
start
,
now
@lazyproperty
def
grading_context
(
self
):
...
...
common/lib/xmodule/xmodule/tests/test_course_module.py
View file @
550e805b
import
unittest
from
time
import
strptime
,
gmtime
from
time
import
strptime
from
fs.memoryfs
import
MemoryFS
from
mock
import
Mock
,
patch
...
...
@@ -39,52 +39,81 @@ class DummySystem(ImportSystem):
class
IsNewCourseTestCase
(
unittest
.
TestCase
):
"""Make sure the property is_new works on courses"""
@staticmethod
def
get_dummy_course
(
start
,
is_new
=
None
,
load_error_modules
=
Tru
e
):
def
get_dummy_course
(
start
,
announcement
=
None
,
is_new
=
Non
e
):
"""Get a dummy course"""
system
=
DummySystem
(
load_error_modules
)
is_new
=
''
if
is_new
is
None
else
'is_new="{0}"'
.
format
(
is_new
)
.
lower
()
system
=
DummySystem
(
load_error_modules
=
True
)
def
to_attrb
(
n
,
v
):
return
''
if
v
is
None
else
'{0}="{1}"'
.
format
(
n
,
v
)
.
lower
()
is_new
=
to_attrb
(
'is_new'
,
is_new
)
announcement
=
to_attrb
(
'announcement'
,
announcement
)
start_xml
=
'''
<course org="{org}" course="{course}"
graceperiod="1 day" url_name="test"
start="{start}"
{announcement}
{is_new}>
<chapter url="hi" url_name="ch" display_name="CH">
<html url_name="h" display_name="H">Two houses, ...</html>
</chapter>
</course>
'''
.
format
(
org
=
ORG
,
course
=
COURSE
,
start
=
start
,
is_new
=
is_new
)
'''
.
format
(
org
=
ORG
,
course
=
COURSE
,
start
=
start
,
is_new
=
is_new
,
announcement
=
announcement
)
return
system
.
process_xml
(
start_xml
)
@patch
(
'xmodule.course_module.time.gmtime'
)
def
test_non_started_yet
(
self
,
gmtime_mock
):
descriptor
=
self
.
get_dummy_course
(
start
=
'2013-01-05T12:00'
)
gmtime_mock
.
return_value
=
NOW
assert
(
descriptor
.
is_new
==
True
)
assert
(
descriptor
.
days_until_start
==
4
)
@patch
(
'xmodule.course_module.time.gmtime'
)
def
test_already_started
(
self
,
gmtime_mock
):
def
test_sorting_score
(
self
,
gmtime_mock
):
gmtime_mock
.
return_value
=
NOW
dates
=
[(
'2012-10-01T12:00'
,
'2012-09-01T12:00'
),
# 0
(
'2012-12-01T12:00'
,
'2012-11-01T12:00'
),
# 1
(
'2013-02-01T12:00'
,
'2012-12-01T12:00'
),
# 2
(
'2013-02-01T12:00'
,
'2012-11-10T12:00'
),
# 3
(
'2013-02-01T12:00'
,
None
),
# 4
(
'2013-03-01T12:00'
,
None
),
# 5
(
'2013-04-01T12:00'
,
None
),
# 6
(
'2012-11-01T12:00'
,
None
),
# 7
(
'2012-09-01T12:00'
,
None
),
# 8
(
'1990-01-01T12:00'
,
None
),
# 9
(
'2013-01-02T12:00'
,
None
),
# 10
(
'2013-01-10T12:00'
,
'2012-12-31T12:00'
),
# 11
(
'2013-01-10T12:00'
,
'2013-01-01T12:00'
),
# 12
]
data
=
[]
for
i
,
d
in
enumerate
(
dates
):
descriptor
=
self
.
get_dummy_course
(
start
=
d
[
0
],
announcement
=
d
[
1
])
score
=
descriptor
.
sorting_score
data
.
append
((
score
,
i
))
result
=
[
d
[
1
]
for
d
in
sorted
(
data
)]
assert
(
result
==
[
12
,
11
,
2
,
3
,
1
,
0
,
6
,
5
,
4
,
10
,
7
,
8
,
9
])
descriptor
=
self
.
get_dummy_course
(
start
=
'2012-12-02T12:00'
)
assert
(
descriptor
.
is_new
==
False
)
assert
(
descriptor
.
days_until_start
<
0
)
@patch
(
'xmodule.course_module.time.gmtime'
)
def
test_is_new
_set
(
self
,
gmtime_mock
):
def
test_is_new
(
self
,
gmtime_mock
):
gmtime_mock
.
return_value
=
NOW
descriptor
=
self
.
get_dummy_course
(
start
=
'2012-12-02T12:00'
,
is_new
=
True
)
assert
(
descriptor
.
is_new
==
True
)
assert
(
descriptor
.
days_until_start
<
0
)
assert
(
descriptor
.
is_new
is
True
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2013-02-02T12:00'
,
is_new
=
False
)
assert
(
descriptor
.
is_new
==
False
)
assert
(
descriptor
.
days_until_start
>
0
)
assert
(
descriptor
.
is_new
is
False
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2013-02-02T12:00'
,
is_new
=
True
)
assert
(
descriptor
.
is_new
==
True
)
assert
(
descriptor
.
days_until_start
>
0
)
assert
(
descriptor
.
is_new
is
True
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2013-01-15T12:00'
)
assert
(
descriptor
.
is_new
is
True
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2013-03-00T12:00'
)
assert
(
descriptor
.
is_new
is
True
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2012-10-15T12:00'
)
assert
(
descriptor
.
is_new
is
False
)
descriptor
=
self
.
get_dummy_course
(
start
=
'2012-12-31T12:00'
)
assert
(
descriptor
.
is_new
is
True
)
lms/djangoapps/courseware/courses.py
View file @
550e805b
...
...
@@ -95,6 +95,7 @@ def course_image_url(course):
path
=
StaticContent
.
get_url_path_from_location
(
loc
)
return
path
def
find_file
(
fs
,
dirs
,
filename
):
"""
Looks for a filename in a list of dirs on a filesystem, in the specified order.
...
...
@@ -111,6 +112,7 @@ def find_file(fs, dirs, filename):
return
filepath
raise
ResourceNotFoundError
(
"Could not find {0}"
.
format
(
filename
))
def
get_course_about_section
(
course
,
section_key
):
"""
This returns the snippet of html to be rendered on the course about page,
...
...
@@ -256,4 +258,18 @@ def get_courses(user, domain=None):
courses
=
[
c
for
c
in
courses
if
has_access
(
user
,
c
,
'see_exists'
)]
courses
=
sorted
(
courses
,
key
=
lambda
course
:
course
.
number
)
return
courses
def
sort_by_announcement
(
courses
):
"""
Sorts a list of courses by their announcement date. If the date is
not available, sort them by their start date.
"""
# Sort courses by how far are they from they start day
key
=
lambda
course
:
course
.
sorting_score
courses
=
sorted
(
courses
,
key
=
key
)
return
courses
lms/djangoapps/courseware/views.py
View file @
550e805b
...
...
@@ -17,7 +17,8 @@ from django.views.decorators.cache import cache_control
from
courseware
import
grades
from
courseware.access
import
has_access
from
courseware.courses
import
(
get_courses
,
get_course_with_access
,
get_courses_by_university
)
from
courseware.courses
import
(
get_courses
,
get_course_with_access
,
get_courses_by_university
,
sort_by_announcement
)
import
courseware.tabs
as
tabs
from
courseware.models
import
StudentModuleCache
from
module_render
import
toc_for_course
,
get_module
,
get_instance_module
,
get_module_for_descriptor
...
...
@@ -67,11 +68,8 @@ def courses(request):
'''
Render "find courses" page. The course selection work is done in courseware.courses.
'''
courses
=
get_courses
(
request
.
user
,
domain
=
request
.
META
.
get
(
'HTTP_HOST'
))
# Sort courses by how far are they from they start day
key
=
lambda
course
:
course
.
days_until_start
courses
=
sorted
(
courses
,
key
=
key
,
reverse
=
True
)
courses
=
get_courses
(
request
.
user
,
request
.
META
.
get
(
'HTTP_HOST'
))
courses
=
sort_by_announcement
(
courses
)
return
render_to_response
(
"courseware/courses.html"
,
{
'courses'
:
courses
})
...
...
@@ -437,10 +435,7 @@ def university_profile(request, org_id):
# Only grab courses for this org...
courses
=
get_courses_by_university
(
request
.
user
,
domain
=
request
.
META
.
get
(
'HTTP_HOST'
))[
org_id
]
# Sort courses by how far are they from they start day
key
=
lambda
course
:
course
.
days_until_start
courses
=
sorted
(
courses
,
key
=
key
,
reverse
=
True
)
courses
=
sort_by_announcement
(
courses
)
context
=
dict
(
courses
=
courses
,
org_id
=
org_id
)
template_file
=
"university_profile/{0}.html"
.
format
(
org_id
)
.
lower
()
...
...
lms/djangoapps/instructor/views.py
View file @
550e805b
...
...
@@ -111,6 +111,7 @@ def instructor_dashboard(request, course_id):
except
Group
.
DoesNotExist
:
group
=
Group
(
name
=
grpname
)
# create the group
group
.
save
()
return
group
def
get_beta_group
(
course
):
"""
...
...
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