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
0b903264
Commit
0b903264
authored
Nov 24, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MA-1667: Update Mobile API to support Web Certificates
parent
a7e21bf1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
105 additions
and
52 deletions
+105
-52
lms/djangoapps/certificates/api.py
+1
-1
lms/djangoapps/certificates/tests/test_api.py
+74
-46
lms/djangoapps/mobile_api/users/serializers.py
+6
-4
lms/djangoapps/mobile_api/users/tests.py
+24
-1
No files found.
lms/djangoapps/certificates/api.py
View file @
0b903264
...
...
@@ -183,7 +183,7 @@ def certificate_downloadable_status(student, course_key):
if
current_status
[
'status'
]
==
CertificateStatuses
.
downloadable
:
response_data
[
'is_downloadable'
]
=
True
response_data
[
'download_url'
]
=
current_status
[
'download_url'
]
response_data
[
'download_url'
]
=
get_certificate_url
(
student
.
id
,
course_key
)
return
response_data
...
...
lms/djangoapps/certificates/tests/test_api.py
View file @
0b903264
...
...
@@ -31,8 +31,57 @@ FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED
[
'CERTIFICATES_HTML_VIEW'
]
=
True
class
WebCertificateTestMixin
(
object
):
"""
Mixin with helpers for testing Web Certificates.
"""
@contextmanager
def
_mock_passing_grade
(
self
):
"""
Mock the grading function to always return a passing grade.
"""
symbol
=
'courseware.grades.grade'
with
patch
(
symbol
)
as
mock_grade
:
mock_grade
.
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
yield
@contextmanager
def
_mock_queue
(
self
,
is_successful
=
True
):
"""
Mock the "send to XQueue" method to return either success or an error.
"""
symbol
=
'capa.xqueue_interface.XQueueInterface.send_to_queue'
with
patch
(
symbol
)
as
mock_send_to_queue
:
if
is_successful
:
mock_send_to_queue
.
return_value
=
(
0
,
"Successfully queued"
)
else
:
mock_send_to_queue
.
side_effect
=
XQueueAddToQueueError
(
1
,
self
.
ERROR_REASON
)
yield
mock_send_to_queue
def
_setup_course_certificate
(
self
):
"""
Creates certificate configuration for course
"""
certificates
=
[
{
'id'
:
1
,
'name'
:
'Test Certificate Name'
,
'description'
:
'Test Certificate Description'
,
'course_title'
:
'tes_course_title'
,
'signatories'
:
[],
'version'
:
1
,
'is_active'
:
True
}
]
self
.
course
.
certificates
=
{
'certificates'
:
certificates
}
self
.
course
.
cert_html_view_enabled
=
True
self
.
course
.
save
()
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
@attr
(
'shard_1'
)
class
CertificateDownloadableStatusTests
(
ModuleStoreTestCase
):
class
CertificateDownloadableStatusTests
(
WebCertificateTestMixin
,
ModuleStoreTestCase
):
"""Tests for the `certificate_downloadable_status` helper function. """
def
setUp
(
self
):
...
...
@@ -48,7 +97,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
self
.
request_factory
=
RequestFactory
()
def
test_
user_
cert_status_with_generating
(
self
):
def
test_cert_status_with_generating
(
self
):
GeneratedCertificateFactory
.
create
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
,
...
...
@@ -65,7 +114,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def
test_
user_
cert_status_with_error
(
self
):
def
test_cert_status_with_error
(
self
):
GeneratedCertificateFactory
.
create
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
,
...
...
@@ -82,7 +131,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def
test_
user_with_
out_cert
(
self
):
def
test_
with
out_cert
(
self
):
self
.
assertEqual
(
certs_api
.
certificate_downloadable_status
(
self
.
student_no_cert
,
self
.
course
.
id
),
{
...
...
@@ -92,7 +141,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def
test_
user_with_downloadable
_cert
(
self
):
def
test_
with_downloadable_pdf
_cert
(
self
):
GeneratedCertificateFactory
.
create
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
,
...
...
@@ -110,10 +159,29 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
@patch.dict
(
settings
.
FEATURES
,
{
'CERTIFICATES_HTML_VIEW'
:
True
})
def
test_with_downloadable_web_cert
(
self
):
CourseEnrollment
.
enroll
(
self
.
student
,
self
.
course
.
id
,
mode
=
'honor'
)
self
.
_setup_course_certificate
()
with
self
.
_mock_passing_grade
():
certs_api
.
generate_user_certificates
(
self
.
student
,
self
.
course
.
id
)
self
.
assertEqual
(
certs_api
.
certificate_downloadable_status
(
self
.
student
,
self
.
course
.
id
),
{
'is_downloadable'
:
True
,
'is_generating'
:
False
,
'download_url'
:
'/certificates/user/{user_id}/course/{course_id}'
.
format
(
user_id
=
self
.
student
.
id
,
# pylint: disable=no-member
course_id
=
self
.
course
.
id
,
),
}
)
@attr
(
'shard_1'
)
@override_settings
(
CERT_QUEUE
=
'certificates'
)
class
GenerateUserCertificatesTest
(
EventTestMixin
,
ModuleStoreTestCase
):
class
GenerateUserCertificatesTest
(
EventTestMixin
,
WebCertificateTestMixin
,
ModuleStoreTestCase
):
"""Tests for generating certificates for students. """
ERROR_REASON
=
"Kaboom!"
...
...
@@ -185,46 +253,6 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
url
=
certs_api
.
get_certificate_url
(
self
.
student
.
id
,
self
.
course
.
id
)
self
.
assertEqual
(
url
,
""
)
@contextmanager
def
_mock_passing_grade
(
self
):
"""Mock the grading function to always return a passing grade. """
symbol
=
'courseware.grades.grade'
with
patch
(
symbol
)
as
mock_grade
:
mock_grade
.
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
yield
@contextmanager
def
_mock_queue
(
self
,
is_successful
=
True
):
"""Mock the "send to XQueue" method to return either success or an error. """
symbol
=
'capa.xqueue_interface.XQueueInterface.send_to_queue'
with
patch
(
symbol
)
as
mock_send_to_queue
:
if
is_successful
:
mock_send_to_queue
.
return_value
=
(
0
,
"Successfully queued"
)
else
:
mock_send_to_queue
.
side_effect
=
XQueueAddToQueueError
(
1
,
self
.
ERROR_REASON
)
yield
mock_send_to_queue
def
_setup_course_certificate
(
self
):
"""
Creates certificate configuration for course
"""
certificates
=
[
{
'id'
:
1
,
'name'
:
'Test Certificate Name'
,
'description'
:
'Test Certificate Description'
,
'course_title'
:
'tes_course_title'
,
'signatories'
:
[],
'version'
:
1
,
'is_active'
:
True
}
]
self
.
course
.
certificates
=
{
'certificates'
:
certificates
}
self
.
course
.
cert_html_view_enabled
=
True
self
.
course
.
save
()
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
@attr
(
'shard_1'
)
@ddt.ddt
...
...
lms/djangoapps/mobile_api/users/serializers.py
View file @
0b903264
...
...
@@ -8,7 +8,7 @@ from django.template import defaultfilters
from
courseware.access
import
has_access
from
student.models
import
CourseEnrollment
,
User
from
certificates.
models
import
certificate_status_for_student
,
CertificateStatuse
s
from
certificates.
api
import
certificate_downloadable_statu
s
from
xmodule.course_module
import
DEFAULT_START_DATE
...
...
@@ -89,10 +89,12 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
def
get_certificate
(
self
,
model
):
"""Returns the information about the user's certificate in the course."""
certificate_info
=
certificate_
status_for_student
(
model
.
user
,
model
.
course_id
)
if
certificate_info
[
'
status'
]
==
CertificateStatuses
.
downloadable
:
certificate_info
=
certificate_
downloadable_status
(
model
.
user
,
model
.
course_id
)
if
certificate_info
[
'
is_downloadable'
]
:
return
{
"url"
:
certificate_info
[
'download_url'
],
'url'
:
self
.
context
[
'request'
]
.
build_absolute_uri
(
certificate_info
[
'download_url'
]
),
}
else
:
return
{}
...
...
lms/djangoapps/mobile_api/users/tests.py
View file @
0b903264
"""
Tests for users API
"""
# pylint: disable=no-member
import
datetime
import
ddt
from
mock
import
patch
...
...
@@ -10,6 +11,7 @@ from django.conf import settings
from
django.utils
import
timezone
from
django.template
import
defaultfilters
from
certificates.api
import
generate_user_certificates
from
certificates.models
import
CertificateStatuses
from
certificates.tests.factories
import
GeneratedCertificateFactory
from
courseware.access_response
import
(
...
...
@@ -180,7 +182,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
certificate_data
=
response
.
data
[
0
][
'certificate'
]
self
.
assertDictEqual
(
certificate_data
,
{})
def
test_certificate
(
self
):
def
test_
pdf_
certificate
(
self
):
self
.
login_and_enroll
()
certificate_url
=
"http://test_certificate_url"
...
...
@@ -196,6 +198,27 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
certificate_data
=
response
.
data
[
0
][
'certificate'
]
self
.
assertEquals
(
certificate_data
[
'url'
],
certificate_url
)
@patch.dict
(
settings
.
FEATURES
,
{
'CERTIFICATES_HTML_VIEW'
:
True
})
def
test_web_certificate
(
self
):
self
.
login_and_enroll
()
self
.
course
.
cert_html_view_enabled
=
True
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
with
patch
(
'courseware.grades.grade'
)
as
mock_grade
:
mock_grade
.
return_value
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
generate_user_certificates
(
self
.
user
,
self
.
course
.
id
)
response
=
self
.
api_response
()
certificate_data
=
response
.
data
[
0
][
'certificate'
]
self
.
assertRegexpMatches
(
certificate_data
[
'url'
],
r'http.*/certificates/user/{user_id}/course/{course_id}'
.
format
(
user_id
=
self
.
user
.
id
,
course_id
=
self
.
course
.
id
,
)
)
def
test_no_facebook_url
(
self
):
self
.
login_and_enroll
()
...
...
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