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
115d8c64
Commit
115d8c64
authored
10 years ago
by
Adam
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4320 from edx/merge-rc-to-master
Merge rc to master
parents
5f11aa9a
d63a5abf
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
122 additions
and
22 deletions
+122
-22
common/djangoapps/student/models.py
+8
-1
common/djangoapps/student/tests/tests.py
+23
-0
lms/djangoapps/certificates/models.py
+15
-1
lms/djangoapps/certificates/tests/__init__.py
+0
-0
lms/djangoapps/certificates/tests/factories.py
+16
-0
lms/djangoapps/certificates/tests/tests.py
+24
-0
lms/djangoapps/instructor/views/instructor_dashboard.py
+33
-17
lms/urls.py
+1
-1
requirements/edx/github.txt
+2
-2
No files found.
common/djangoapps/student/models.py
View file @
115d8c64
...
...
@@ -36,13 +36,15 @@ from importlib import import_module
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
course_modes.models
import
CourseMode
import
lms.lib.comment_client
as
cc
from
util.query
import
use_read_replica_if_available
from
xmodule_django.models
import
CourseKeyField
,
NoneToEmptyManager
from
opaque_keys.edx.keys
import
CourseKey
from
functools
import
total_ordering
from
certificates.models
import
GeneratedCertificate
from
course_modes.models
import
CourseMode
unenroll_done
=
Signal
(
providing_args
=
[
"course_enrollment"
])
log
=
logging
.
getLogger
(
__name__
)
AUDIT_LOG
=
logging
.
getLogger
(
"audit"
)
...
...
@@ -953,6 +955,11 @@ class CourseEnrollment(models.Model):
# (side-effects are bad)
if
getattr
(
self
,
'can_refund'
,
None
)
is
not
None
:
return
True
# If the student has already been given a certificate they should not be refunded
if
GeneratedCertificate
.
certificate_for_student
(
self
.
user
,
self
.
course_id
)
is
not
None
:
return
False
course_mode
=
CourseMode
.
mode_for_course
(
self
.
course_id
,
'verified'
)
if
course_mode
is
None
:
return
False
...
...
This diff is collapsed.
Click to expand it.
common/djangoapps/student/tests/tests.py
View file @
115d8c64
...
...
@@ -30,6 +30,8 @@ from student.views import (process_survey_link, _cert_info,
change_enrollment
,
complete_course_mode_info
)
from
student.tests.factories
import
UserFactory
,
CourseModeFactory
from
certificates.models
import
CertificateStatuses
from
certificates.tests.factories
import
GeneratedCertificateFactory
import
shoppingcart
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -212,6 +214,7 @@ class DashboardTest(TestCase):
self
.
assertFalse
(
course_mode_info
[
'show_upsell'
])
self
.
assertIsNone
(
course_mode_info
[
'days_for_upsell'
])
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
def
test_refundable
(
self
):
verified_mode
=
CourseModeFactory
.
create
(
course_id
=
self
.
course
.
id
,
...
...
@@ -227,6 +230,26 @@ class DashboardTest(TestCase):
verified_mode
.
save
()
self
.
assertFalse
(
enrollment
.
refundable
())
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
def
test_refundable_when_certificate_exists
(
self
):
verified_mode
=
CourseModeFactory
.
create
(
course_id
=
self
.
course
.
id
,
mode_slug
=
'verified'
,
mode_display_name
=
'Verified'
,
expiration_datetime
=
datetime
.
now
(
pytz
.
UTC
)
+
timedelta
(
days
=
1
)
)
enrollment
=
CourseEnrollment
.
enroll
(
self
.
user
,
self
.
course
.
id
,
mode
=
'verified'
)
self
.
assertTrue
(
enrollment
.
refundable
())
generated_certificate
=
GeneratedCertificateFactory
.
create
(
user
=
self
.
user
,
course_id
=
self
.
course
.
id
,
status
=
CertificateStatuses
.
downloadable
,
mode
=
'verified'
)
self
.
assertFalse
(
enrollment
.
refundable
())
class
EnrollInCourseTest
(
TestCase
):
"""Tests enrolling and unenrolling in courses."""
...
...
This diff is collapsed.
Click to expand it.
lms/djangoapps/certificates/models.py
View file @
115d8c64
...
...
@@ -81,6 +81,9 @@ class CertificateWhitelist(models.Model):
class
GeneratedCertificate
(
models
.
Model
):
MODES
=
Choices
(
'verified'
,
'honor'
,
'audit'
)
user
=
models
.
ForeignKey
(
User
)
course_id
=
CourseKeyField
(
max_length
=
255
,
blank
=
True
,
default
=
None
)
verify_uuid
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
default
=
''
)
...
...
@@ -90,7 +93,6 @@ class GeneratedCertificate(models.Model):
key
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
default
=
''
)
distinction
=
models
.
BooleanField
(
default
=
False
)
status
=
models
.
CharField
(
max_length
=
32
,
default
=
'unavailable'
)
MODES
=
Choices
(
'verified'
,
'honor'
,
'audit'
)
mode
=
models
.
CharField
(
max_length
=
32
,
choices
=
MODES
,
default
=
MODES
.
honor
)
name
=
models
.
CharField
(
blank
=
True
,
max_length
=
255
)
created_date
=
models
.
DateTimeField
(
...
...
@@ -102,6 +104,18 @@ class GeneratedCertificate(models.Model):
class
Meta
:
unique_together
=
((
'user'
,
'course_id'
),)
@classmethod
def
certificate_for_student
(
cls
,
student
,
course_id
):
"""
This returns the certificate for a student for a particular course
or None if no such certificate exits.
"""
try
:
return
cls
.
objects
.
get
(
user
=
student
,
course_id
=
course_id
)
except
cls
.
DoesNotExist
:
pass
return
None
def
certificate_status_for_student
(
student
,
course_id
):
'''
...
...
This diff is collapsed.
Click to expand it.
lms/djangoapps/certificates/tests/__init__.py
0 → 100644
View file @
115d8c64
This diff is collapsed.
Click to expand it.
lms/djangoapps/certificates/tests/factories.py
0 → 100644
View file @
115d8c64
from
factory.django
import
DjangoModelFactory
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
certificates.models
import
GeneratedCertificate
,
CertificateStatuses
# Factories don't have __init__ methods, and are self documenting
# pylint: disable=W0232
class
GeneratedCertificateFactory
(
DjangoModelFactory
):
FACTORY_FOR
=
GeneratedCertificate
course_id
=
None
status
=
CertificateStatuses
.
unavailable
mode
=
GeneratedCertificate
.
MODES
.
honor
name
=
''
This diff is collapsed.
Click to expand it.
lms/djangoapps/certificates/tests/tests.py
0 → 100644
View file @
115d8c64
"""
Tests for the certificates models.
"""
from
django.test
import
TestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
student.tests.factories
import
UserFactory
from
certificates.models
import
CertificateStatuses
,
GeneratedCertificate
,
certificate_status_for_student
class
CertificatesModelTest
(
TestCase
):
"""
Tests for the GeneratedCertificate model
"""
def
test_certificate_status_for_student
(
self
):
student
=
UserFactory
()
course
=
CourseFactory
.
create
(
org
=
'edx'
,
number
=
'verified'
,
display_name
=
'Verified Course'
)
certificate_status
=
certificate_status_for_student
(
student
,
course
.
id
)
self
.
assertEqual
(
certificate_status
[
'status'
],
CertificateStatuses
.
unavailable
)
self
.
assertEqual
(
certificate_status
[
'mode'
],
GeneratedCertificate
.
MODES
.
honor
)
This diff is collapsed.
Click to expand it.
lms/djangoapps/instructor/views/instructor_dashboard.py
View file @
115d8c64
...
...
@@ -2,6 +2,8 @@
Instructor Dashboard Views
"""
import
logging
from
django.utils.translation
import
ugettext
as
_
from
django_future.csrf
import
ensure_csrf_cookie
from
django.views.decorators.cache
import
cache_control
...
...
@@ -27,12 +29,14 @@ from student.models import CourseEnrollment
from
bulk_email.models
import
CourseAuthorization
from
class_dashboard.dashboard_data
import
get_section_display_name
,
get_array_section_has_problem
from
analyticsclient.client
import
RestClient
from
analyticsclient.client
import
RestClient
,
ClientError
from
analyticsclient.course
import
Course
from
.tools
import
get_units_with_due_date
,
title_or_url
,
bulk_email_is_enabled_for_course
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
log
=
logging
.
getLogger
(
__name__
)
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
...
...
@@ -250,22 +254,7 @@ def _section_analytics(course_key, access):
}
if
settings
.
FEATURES
.
get
(
'ENABLE_ANALYTICS_ACTIVE_COUNT'
):
auth_token
=
settings
.
ANALYTICS_DATA_TOKEN
base_url
=
settings
.
ANALYTICS_DATA_URL
client
=
RestClient
(
base_url
=
base_url
,
auth_token
=
auth_token
)
course
=
Course
(
client
,
course_key
)
section_data
[
'active_student_count'
]
=
course
.
recent_active_user_count
[
'count'
]
def
format_date
(
value
):
return
value
.
split
(
'T'
)[
0
]
start
=
course
.
recent_active_user_count
[
'interval_start'
]
end
=
course
.
recent_active_user_count
[
'interval_end'
]
section_data
[
'active_student_count_start'
]
=
format_date
(
start
)
section_data
[
'active_student_count_end'
]
=
format_date
(
end
)
_update_active_students
(
course_key
,
section_data
)
return
section_data
...
...
@@ -284,3 +273,30 @@ def _section_metrics(course_key, access):
'post_metrics_data_csv_url'
:
reverse
(
'post_metrics_data_csv'
),
}
return
section_data
def
_update_active_students
(
course_key
,
section_data
):
auth_token
=
settings
.
ANALYTICS_DATA_TOKEN
base_url
=
settings
.
ANALYTICS_DATA_URL
section_data
[
'active_student_count'
]
=
'N/A'
section_data
[
'active_student_count_start'
]
=
'N/A'
section_data
[
'active_student_count_end'
]
=
'N/A'
try
:
client
=
RestClient
(
base_url
=
base_url
,
auth_token
=
auth_token
)
course
=
Course
(
client
,
course_key
.
to_deprecated_string
())
section_data
[
'active_student_count'
]
=
course
.
recent_active_user_count
[
'count'
]
def
format_date
(
value
):
return
value
.
split
(
'T'
)[
0
]
start
=
course
.
recent_active_user_count
[
'interval_start'
]
end
=
course
.
recent_active_user_count
[
'interval_end'
]
section_data
[
'active_student_count_start'
]
=
format_date
(
start
)
section_data
[
'active_student_count_end'
]
=
format_date
(
end
)
except
(
ClientError
,
KeyError
)
as
e
:
log
.
exception
(
e
)
This diff is collapsed.
Click to expand it.
lms/urls.py
View file @
115d8c64
...
...
@@ -99,7 +99,7 @@ if settings.FEATURES["ENABLE_SYSADMIN_DASHBOARD"]:
)
urlpatterns
+=
(
url
(
r'support/'
,
include
(
'dashboard.support_urls'
)),
url
(
r'
^
support/'
,
include
(
'dashboard.support_urls'
)),
)
#Semi-static views (these need to be rendered and have the login bar, but don't change)
...
...
This diff is collapsed.
Click to expand it.
requirements/edx/github.txt
View file @
115d8c64
...
...
@@ -27,7 +27,7 @@
-e git+https://github.com/edx/bok-choy.git@82b4e82d79b9d4c6d087ebbfa26ea23235728e62#egg=bok_choy
-e git+https://github.com/edx-solutions/django-splash.git@9965a53c269666a30bb4e2b3f6037c138aef2a55#egg=django-splash
-e git+https://github.com/edx/acid-block.git@459aff7b63db8f2c5decd1755706c1a64fb4ebb1#egg=acid-xblock
-e git+https://github.com/edx/edx-ora2.git@release-2014-06-
30T13.3
9#egg=edx-ora2
-e git+https://github.com/edx/edx-ora2.git@release-2014-06-
23T13.1
9#egg=edx-ora2
-e git+https://github.com/edx/opaque-keys.git@5929789900b3d0a354ce7274bde74edfd0430f03#egg=opaque-keys
-e git+https://github.com/edx/ease.git@
f9f47fb6b5c7c8b6c3360efa72eb56561e1a03b0
#egg=ease
-e git+https://github.com/edx/ease.git@
97de68448e5495385ba043d3091f570a699d5b5f
#egg=ease
-e git+https://github.com/edx/i18n-tools.git@f5303e82dff368c7595884d9325aeea1d802da25#egg=i18n-tools
This diff is collapsed.
Click to expand it.
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