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
987889fc
Commit
987889fc
authored
Jun 05, 2015
by
aamir-khan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ECOM-1524: Display credit availability on the dashboard
parent
13dbfb86
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
460 additions
and
28 deletions
+460
-28
common/djangoapps/student/views.py
+53
-5
lms/envs/common.py
+10
-0
lms/static/sass/multicourse/_dashboard.scss
+4
-0
lms/templates/dashboard.html
+2
-1
lms/templates/dashboard/_dashboard_course_listing.html
+6
-2
lms/templates/dashboard/_dashboard_credit_information.html
+70
-0
openedx/core/djangoapps/credit/api.py
+135
-5
openedx/core/djangoapps/credit/migrations/0009_auto__del_field_crediteligibility_provider.py
+0
-0
openedx/core/djangoapps/credit/models.py
+37
-5
openedx/core/djangoapps/credit/tests/test_api.py
+143
-9
openedx/core/djangoapps/credit/tests/test_views.py
+0
-1
No files found.
common/djangoapps/student/views.py
View file @
987889fc
...
...
@@ -7,8 +7,10 @@ import uuid
import
time
import
json
import
warnings
from
datetime
import
timedelta
from
collections
import
defaultdict
from
pytz
import
UTC
from
requests
import
HTTPError
from
ipware.ip
import
get_ip
from
django.conf
import
settings
...
...
@@ -25,21 +27,19 @@ from django.db import IntegrityError, transaction
from
django.http
import
(
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
,
HttpResponseServerError
,
Http404
)
from
django.shortcuts
import
redirect
from
django.utils
import
timezone
from
django.utils.translation
import
ungettext
from
django.utils.http
import
cookie_date
,
base36_to_int
from
django.utils.translation
import
ugettext
as
_
,
get_language
from
django.views.decorators.cache
import
never_cache
from
django.views.decorators.csrf
import
csrf_exempt
,
ensure_csrf_cookie
from
django.views.decorators.http
import
require_POST
,
require_GET
from
django.db.models.signals
import
post_save
from
django.dispatch
import
receiver
from
django.template.response
import
TemplateResponse
from
ratelimitbackend.exceptions
import
RateLimitException
from
requests
import
HTTPError
from
social.apps.django_app
import
utils
as
social_utils
from
social.backends
import
oauth
as
social_oauth
...
...
@@ -123,13 +123,12 @@ from notification_prefs.views import enable_notifications
# Note that this lives in openedx, so this dependency should be refactored.
from
openedx.core.djangoapps.user_api.preferences
import
api
as
preferences_api
from
openedx.core.djangoapps.credit.api
import
get_credit_eligibility
,
get_purchased_credit_courses
log
=
logging
.
getLogger
(
"edx.student"
)
AUDIT_LOG
=
logging
.
getLogger
(
"audit"
)
ReverifyInfo
=
namedtuple
(
'ReverifyInfo'
,
'course_id course_name course_number date status display'
)
# pylint: disable=invalid-name
SETTING_CHANGE_INITIATED
=
'edx.user.settings.change_initiated'
...
...
@@ -523,6 +522,13 @@ def dashboard(request):
course_enrollment_pairs
,
course_modes_by_course
)
# Retrieve the course modes for each course
enrolled_courses_dict
=
{}
for
course
,
__
in
course_enrollment_pairs
:
enrolled_courses_dict
[
unicode
(
course
.
id
)]
=
course
credit_messages
=
_create_credit_availability_message
(
enrolled_courses_dict
,
user
)
course_optouts
=
Optout
.
objects
.
filter
(
user
=
user
)
.
values_list
(
'course_id'
,
flat
=
True
)
message
=
""
...
...
@@ -628,6 +634,7 @@ def dashboard(request):
context
=
{
'enrollment_message'
:
enrollment_message
,
'credit_messages'
:
credit_messages
,
'course_enrollment_pairs'
:
course_enrollment_pairs
,
'course_optouts'
:
course_optouts
,
'message'
:
message
,
...
...
@@ -692,6 +699,47 @@ def _create_recent_enrollment_message(course_enrollment_pairs, course_modes):
)
def
_create_credit_availability_message
(
enrolled_courses_dict
,
user
):
# pylint: disable=invalid-name
"""Builds a dict of credit availability for courses.
Construct a for courses user has completed and has not purchased credit
from the credit provider yet.
Args:
course_enrollment_pairs (list): A list of tuples containing courses, and the associated enrollment information.
user (User): User object.
Returns:
A dict of courses user is eligible for credit.
"""
user_eligibilities
=
get_credit_eligibility
(
user
.
username
)
user_purchased_credit
=
get_purchased_credit_courses
(
user
.
username
)
eligibility_messages
=
{}
for
course_id
,
eligibility
in
user_eligibilities
.
iteritems
():
if
course_id
not
in
user_purchased_credit
:
duration
=
eligibility
[
"seconds_good_for_display"
]
curr_time
=
timezone
.
now
()
validity_till
=
eligibility
[
"created_at"
]
+
timedelta
(
seconds
=
duration
)
if
validity_till
>
curr_time
:
diff
=
validity_till
-
curr_time
urgent
=
diff
.
days
<=
30
eligibility_messages
[
course_id
]
=
{
"user_id"
:
user
.
id
,
"course_id"
:
course_id
,
"course_name"
:
enrolled_courses_dict
[
course_id
]
.
display_name
,
"providers"
:
eligibility
[
"providers"
],
"status"
:
eligibility
[
"status"
],
"provider"
:
eligibility
.
get
(
"provider"
),
"urgent"
:
urgent
,
"user_full_name"
:
user
.
get_full_name
(),
"expiry"
:
validity_till
}
return
eligibility_messages
def
_get_recently_enrolled_courses
(
course_enrollment_pairs
):
"""Checks to see if the student has recently enrolled in courses.
...
...
lms/envs/common.py
View file @
987889fc
...
...
@@ -1339,6 +1339,12 @@ certificates_web_view_js = [
'js/src/logger.js'
,
]
credit_web_view_js
=
[
'js/vendor/jquery.min.js'
,
'js/vendor/jquery.cookie.js'
,
'js/src/logger.js'
,
]
PIPELINE_CSS
=
{
'style-vendor'
:
{
'source_filenames'
:
[
...
...
@@ -1578,6 +1584,10 @@ PIPELINE_JS = {
'utility'
:
{
'source_filenames'
:
[
'js/src/utility.js'
],
'output_filename'
:
'js/utility.js'
},
'credit_wv'
:
{
'source_filenames'
:
credit_web_view_js
,
'output_filename'
:
'js/credit/web_view.js'
}
}
...
...
lms/static/sass/multicourse/_dashboard.scss
View file @
987889fc
...
...
@@ -531,6 +531,10 @@
padding
:
0
;
}
.purchase_credit
{
float
:
right
;
}
.message
{
@extend
%ui-depth1
;
border-radius
:
3px
;
...
...
lms/templates/dashboard.html
View file @
987889fc
...
...
@@ -83,7 +83,8 @@ from django.core.urlresolvers import reverse
<
%
is_course_blocked =
(course.id
in
block_courses
)
%
>
<
%
course_verification_status =
verification_status_by_course.get(course.id,
{})
%
>
<
%
course_requirements =
courses_requirements_not_met.get(course.id)
%
>
<
%
include
file=
'dashboard/_dashboard_course_listing.html'
args=
"course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option, is_paid_course = is_paid_course, is_course_blocked = is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings"
/>
<
%
credit_message =
credit_messages.get(unicode(course.id))
%
>
<
%
include
file=
'dashboard/_dashboard_course_listing.html'
args=
"course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option, is_paid_course = is_paid_course, is_course_blocked = is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, credit_message=credit_message, user=user"
/>
% endfor
% if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
...
...
lms/templates/dashboard/_dashboard_course_listing.html
View file @
987889fc
<
%
page
args=
"course, enrollment, show_courseware_link, cert_status, show_email_settings, course_mode_info, show_refund_option, is_paid_course, is_course_blocked, verification_status, course_requirements, dashboard_index, share_settings"
/>
<
%
page
args=
"course, enrollment, show_courseware_link, cert_status, show_email_settings, course_mode_info, show_refund_option, is_paid_course, is_course_blocked, verification_status, course_requirements, dashboard_index, share_settings
, credit_message
"
/>
<
%!
import
urllib
...
...
@@ -273,7 +273,11 @@ from student.helpers import (
<ul
class=
"messages-list"
>
% if course.may_certify() and cert_status:
<
%
include
file=
'_dashboard_certificate_information.html'
args=
'cert_status=cert_status,course=course, enrollment=enrollment'
/>
% endif
% endif
% if credit_message:
<
%
include
file=
'_dashboard_credit_information.html'
args=
'credit_message=credit_message'
/>
% endif
% if verification_status.get('status') in [VERIFY_STATUS_NEED_TO_VERIFY, VERIFY_STATUS_SUBMITTED, VERIFY_STATUS_APPROVED, VERIFY_STATUS_NEED_TO_REVERIFY] and not is_course_blocked:
<div
class=
"message message-status wrapper-message-primary is-shown"
>
...
...
lms/templates/dashboard/_dashboard_credit_information.html
0 → 100644
View file @
987889fc
<
%
page
args=
"credit_message"
/>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
from
course_modes
.
models
import
CourseMode
from
util
.
date_utils
import
get_default_time_display
%
>
<
%
namespace
name=
'static'
file=
'../static_content.html'
/>
<
%
block
name=
"js_extra"
args=
"credit_message"
>
<
%
static:js
group=
'credit_wv'
/>
<script
type=
"text/javascript"
>
$
(
document
).
ready
(
function
()
{
$
.
ajaxSetup
({
headers
:
{
'X-CSRFToken'
:
$
.
cookie
(
'csrftoken'
)
},
dataType
:
'json'
});
$
(
".purchase-credit-btn"
).
click
(
function
()
{
var
data
=
{
user_id
:
"${credit_message['user_id']}"
,
course_id
:
"${credit_message['course_id']}"
};
Logger
.
log
(
'edx.credit.shared'
,
data
);
});
});
</script>
</
%
block>
<div
class=
"message message-status is-shown"
>
<p>
% if credit_message["status"] == "requirements_meet":
<span>
% if credit_message["urgent"]:
${_("{username}, your eligibility for credit expires on {expiry}. Don't miss out!").format(
username=credit_message["user_full_name"],
expiry=get_default_time_display(credit_message["expiry"])
)
}
% else:
${_("{congrats} {username}, You have meet requirements for credit.").format(
congrats="
<b>
Congratulations
</b>
",
username=credit_message["user_full_name"]
)
}
% endif
</span>
<span
class=
"purchase_credit"
>
<a
class=
"btn purchase-credit-btn"
href=
""
target=
"_blank"
>
${_("Purchase Credit")}
</a>
</span>
% elif credit_message["status"] == "pending":
${_("Thank you, your payment is complete, your credit is processing. Please see {provider_link} for more information.").format(
provider_link='
<a
href=
"#"
target=
"_blank"
>
{}
</a>
'.format(credit_message["provider"]["display_name"])
)
}
% elif credit_message["status"] == "approved":
${_("Thank you, your credit is approved. Please see {provider_link} for more information.").format(
provider_link='
<a
href=
"#"
target=
"_blank"
>
{}
</a>
'.format(credit_message["provider"]["display_name"])
)
}
% elif credit_message["status"] == "rejected":
${_("Your credit has been denied. Please contact {provider_link} for more information.").format(
provider_link='
<a
href=
"#"
target=
"_blank"
>
{}
</a>
'.format(credit_message["provider"]["display_name"])
)
}
% endif
</p>
</div>
openedx/core/djangoapps/credit/api.py
View file @
987889fc
...
...
@@ -26,6 +26,7 @@ from .exceptions import (
)
from
.models
import
(
CreditCourse
,
CreditProvider
,
CreditRequirement
,
CreditRequirementStatus
,
CreditRequest
,
...
...
@@ -33,6 +34,7 @@ from .models import (
)
from
.signature
import
signature
,
get_shared_secret_key
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -211,14 +213,13 @@ def create_credit_request(course_key, provider_id, username):
"""
try
:
user_eligibility
=
CreditEligibility
.
objects
.
select_related
(
'course'
,
'provider'
)
.
get
(
user_eligibility
=
CreditEligibility
.
objects
.
select_related
(
'course'
)
.
get
(
username
=
username
,
course__course_key
=
course_key
,
provider__provider_id
=
provider_id
course__course_key
=
course_key
)
credit_course
=
user_eligibility
.
course
credit_provider
=
user_eligibility
.
provider
except
CreditEligibility
.
DoesNotExist
:
credit_provider
=
credit_course
.
providers
.
get
(
provider_id
=
provider_id
)
except
(
CreditEligibility
.
DoesNotExist
,
CreditProvider
.
DoesNotExist
)
:
log
.
warning
(
u'User tried to initiate a request for credit, but the user is not eligible for credit'
)
raise
UserIsNotEligible
...
...
@@ -614,3 +615,132 @@ def is_credit_course(course_key):
return
False
return
CreditCourse
.
is_credit_course
(
course_key
=
course_key
)
def
get_credit_request_status
(
username
,
course_key
):
"""Get the credit request status.
This function returns the status of credit request of user for given course.
It returns the latest request status for the any credit provider.
The valid status are 'pending', 'approved' or 'rejected'.
Args:
username(str): The username of user
course_key(CourseKey): The course locator key
Returns:
A dictionary of credit request user has made if any
"""
credit_request
=
CreditRequest
.
get_user_request_status
(
username
,
course_key
)
if
credit_request
:
credit_status
=
{
"uuid"
:
credit_request
.
uuid
,
"timestamp"
:
credit_request
.
modified
,
"course_key"
:
credit_request
.
course
.
course_key
,
"provider"
:
{
"id"
:
credit_request
.
provider
.
provider_id
,
"display_name"
:
credit_request
.
provider
.
display_name
},
"status"
:
credit_request
.
status
}
else
:
credit_status
=
{}
return
credit_status
def
_get_duration_and_providers
(
credit_course
):
"""Returns the credit providers and eligibility durations.
The eligibility_duration is the max of the credit duration of
all the credit providers of given course.
Args:
credit_course(CreditCourse): The CreditCourse object
Returns:
Tuple of eligibility_duration and credit providers of given course
"""
providers
=
credit_course
.
providers
.
all
()
seconds_good_for_display
=
0
providers_list
=
[]
for
provider
in
providers
:
providers_list
.
append
(
{
"id"
:
provider
.
provider_id
,
"display_name"
:
provider
.
display_name
,
"eligibility_duration"
:
provider
.
eligibility_duration
,
"provider_url"
:
provider
.
provider_url
}
)
eligibility_duration
=
int
(
provider
.
eligibility_duration
)
if
provider
.
eligibility_duration
else
0
seconds_good_for_display
=
max
(
eligibility_duration
,
seconds_good_for_display
)
return
seconds_good_for_display
,
providers_list
def
get_credit_eligibility
(
username
):
"""
Returns the all the eligibility the user has meet.
Args:
username(str): The username of user
Example:
>> get_credit_eligibility('Aamir'):
{
"edX/DemoX/Demo_Course": {
"created_at": "2015-12-21",
"providers": [
"id": 12,
"display_name": "Arizona State University",
"eligibility_duration": 60,
"provider_url": "http://arizona/provideere/link"
],
"seconds_good_for_display": 90
}
}
Returns:
A dict of eligibilities
"""
eligibilities
=
CreditEligibility
.
get_user_eligibility
(
username
)
user_credit_requests
=
get_credit_requests_for_user
(
username
)
request_dict
=
{}
# Change the list to dict for iteration
for
request
in
user_credit_requests
:
request_dict
[
unicode
(
request
[
"course_key"
])]
=
request
user_eligibilities
=
{}
for
eligibility
in
eligibilities
:
course_key
=
eligibility
.
course
.
course_key
duration
,
providers_list
=
_get_duration_and_providers
(
eligibility
.
course
)
user_eligibilities
[
unicode
(
course_key
)]
=
{
"created_at"
:
eligibility
.
created
,
"seconds_good_for_display"
:
duration
,
"providers"
:
providers_list
,
}
# Default status is requirements_meet
user_eligibilities
[
unicode
(
course_key
)][
"status"
]
=
"requirements_meet"
# If there is some request user has made for this eligibility then update the status
if
unicode
(
course_key
)
in
request_dict
:
user_eligibilities
[
unicode
(
course_key
)][
"status"
]
=
request_dict
[
unicode
(
course_key
)][
"status"
]
user_eligibilities
[
unicode
(
course_key
)][
"provider"
]
=
request_dict
[
unicode
(
course_key
)][
"provider"
]
return
user_eligibilities
def
get_purchased_credit_courses
(
username
):
# pylint: disable=unused-argument
"""
Returns the purchased credit courses.
Args:
username(str): Username of the student
Returns:
A dict of courses user has purchased from the credit provider after completion
"""
# TODO: How to track the purchased courses. It requires Will's work for credit provider integration
return
{}
openedx/core/djangoapps/credit/migrations/0009_auto__del_field_crediteligibility_provider.py
0 → 100644
View file @
987889fc
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/credit/models.py
View file @
987889fc
...
...
@@ -307,12 +307,24 @@ class CreditEligibility(TimeStampedModel):
"""
username
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
course
=
models
.
ForeignKey
(
CreditCourse
,
related_name
=
"eligibilities"
)
provider
=
models
.
ForeignKey
(
CreditProvider
,
related_name
=
"eligibilities"
)
class
Meta
(
object
):
# pylint: disable=missing-docstring
unique_together
=
(
'username'
,
'course'
)
@classmethod
def
get_user_eligibility
(
cls
,
username
):
"""Returns the eligibilities of given user.
Args:
username(str): Username of the user
Returns:
CreditEligibility queryset for the user
"""
return
cls
.
objects
.
filter
(
username
=
username
)
.
select_related
(
'course'
)
.
prefetch_related
(
'course__providers'
)
@classmethod
def
is_user_eligible_for_credit
(
cls
,
course_key
,
username
):
"""Check if the given user is eligible for the provided credit course
...
...
@@ -361,6 +373,12 @@ class CreditRequest(TimeStampedModel):
history
=
HistoricalRecords
()
class
Meta
(
object
):
# pylint: disable=missing-docstring
# Enforce the constraint that each user can have exactly one outstanding
# request to a given provider. Multiple requests use the same UUID.
unique_together
=
(
'username'
,
'course'
,
'provider'
)
get_latest_by
=
'created'
@classmethod
def
credit_requests_for_user
(
cls
,
username
):
"""
...
...
@@ -402,7 +420,21 @@ class CreditRequest(TimeStampedModel):
for
request
in
cls
.
objects
.
select_related
(
'course'
,
'provider'
)
.
filter
(
username
=
username
)
]
class
Meta
(
object
):
# pylint: disable=missing-docstring
# Enforce the constraint that each user can have exactly one outstanding
# request to a given provider. Multiple requests use the same UUID.
unique_together
=
(
'username'
,
'course'
,
'provider'
)
@classmethod
def
get_user_request_status
(
cls
,
username
,
course_key
):
"""Returns the latest credit request of user against the given course.
Args:
username(str): The username of requesting user
course_key(CourseKey): The course identifier
Returns:
CreditRequest if any otherwise None
"""
try
:
return
cls
.
objects
.
filter
(
username
=
username
,
course__course_key
=
course_key
)
.
select_related
(
'course'
,
'provider'
)
.
latest
()
except
cls
.
DoesNotExist
:
return
None
openedx/core/djangoapps/credit/tests/test_api.py
View file @
987889fc
"""
Tests for the API functions in the credit app.
"""
import
unittest
import
datetime
import
ddt
import
pytz
from
django.test
import
TestCase
from
django.test.utils
import
override_settings
from
django.db
import
connection
,
transaction
from
django.core.urlresolvers
import
reverse
from
django.conf
import
settings
from
opaque_keys.edx.keys
import
CourseKey
from
student.tests.factories
import
UserFactory
from
util.date_utils
import
from_timestamp
from
openedx.core.djangoapps.credit
import
api
from
openedx.core.djangoapps.credit.exceptions
import
(
...
...
@@ -34,13 +35,20 @@ from openedx.core.djangoapps.credit.api import (
set_credit_requirement_status
,
get_credit_requirement
)
from
student.models
import
CourseEnrollment
from
student.views
import
_create_credit_availability_message
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
TEST_CREDIT_PROVIDER_SECRET_KEY
=
"931433d583c84ca7ba41784bad3232e6"
@override_settings
(
CREDIT_PROVIDER_SECRET_KEYS
=
{
"hogwarts"
:
TEST_CREDIT_PROVIDER_SECRET_KEY
"hogwarts"
:
TEST_CREDIT_PROVIDER_SECRET_KEY
,
"ASU"
:
TEST_CREDIT_PROVIDER_SECRET_KEY
,
"MIT"
:
TEST_CREDIT_PROVIDER_SECRET_KEY
})
class
CreditApiTestBase
(
TestCase
):
"""
...
...
@@ -212,7 +220,7 @@ class CreditRequirementApiTests(CreditApiTestBase):
def
test_is_user_eligible_for_credit
(
self
):
credit_course
=
self
.
add_credit_course
()
CreditEligibility
.
objects
.
create
(
course
=
credit_course
,
username
=
"staff"
,
provider
=
CreditProvider
.
objects
.
get
(
provider_id
=
self
.
PROVIDER_ID
)
course
=
credit_course
,
username
=
"staff"
)
is_eligible
=
api
.
is_user_eligible_for_credit
(
'staff'
,
credit_course
.
course_key
)
self
.
assertTrue
(
is_eligible
)
...
...
@@ -380,19 +388,26 @@ class CreditProviderIntegrationApiTests(CreditApiTestBase):
# Initial status should be "pending"
self
.
_assert_credit_status
(
"pending"
)
credit_request_status
=
api
.
get_credit_request_status
(
self
.
USER_INFO
[
'username'
],
self
.
course_key
)
self
.
assertEqual
(
credit_request_status
[
"status"
],
"pending"
)
# Update the status
api
.
update_credit_request_status
(
request
[
"parameters"
][
"request_uuid"
],
self
.
PROVIDER_ID
,
status
)
self
.
_assert_credit_status
(
status
)
credit_request_status
=
api
.
get_credit_request_status
(
self
.
USER_INFO
[
'username'
],
self
.
course_key
)
self
.
assertEqual
(
credit_request_status
[
"status"
],
status
)
def
test_query_counts
(
self
):
# Yes, this is a lot of queries, but this API call is also doing a lot of work :)
# - 1 query: Check the user's eligibility and retrieve the credit course and provider.
# - 1 query: Check the user's eligibility and retrieve the credit course
# - 1 Get the provider of the credit course.
# - 2 queries: Get-or-create the credit request.
# - 1 query: Retrieve user account and profile information from the user API.
# - 1 query: Look up the user's final grade from the credit requirements table.
# - 2 queries: Update the request.
# - 2 queries: Update the history table for the request.
with
self
.
assertNumQueries
(
9
):
with
self
.
assertNumQueries
(
10
):
request
=
api
.
create_credit_request
(
self
.
course_key
,
self
.
PROVIDER_ID
,
self
.
USER_INFO
[
'username'
])
# - 3 queries: Retrieve and update the request
...
...
@@ -522,12 +537,131 @@ class CreditProviderIntegrationApiTests(CreditApiTestBase):
status
.
save
()
CreditEligibility
.
objects
.
create
(
username
=
self
.
USER_INFO
[
"username"
],
course
=
CreditCourse
.
objects
.
get
(
course_key
=
self
.
course_key
),
provider
=
CreditProvider
.
objects
.
get
(
provider_id
=
self
.
PROVIDER_ID
)
username
=
self
.
USER_INFO
[
'username'
],
course
=
CreditCourse
.
objects
.
get
(
course_key
=
self
.
course_key
)
)
def
_assert_credit_status
(
self
,
expected_status
):
"""Check the user's credit status. """
statuses
=
api
.
get_credit_requests_for_user
(
self
.
USER_INFO
[
"username"
])
self
.
assertEqual
(
statuses
[
0
][
"status"
],
expected_status
)
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
CreditMessagesTests
(
ModuleStoreTestCase
,
CreditApiTestBase
):
"""
Test dashboard messages of credit course.
"""
FINAL_GRADE
=
0.8
def
setUp
(
self
):
super
(
CreditMessagesTests
,
self
)
.
setUp
()
self
.
student
=
UserFactory
()
self
.
student
.
set_password
(
'test'
)
# pylint: disable=no-member
self
.
student
.
save
()
# pylint: disable=no-member
self
.
client
.
login
(
username
=
self
.
student
.
username
,
password
=
'test'
)
# New Course
self
.
course
=
CourseFactory
.
create
()
self
.
enrollment
=
CourseEnrollment
.
enroll
(
self
.
student
,
self
.
course
.
id
)
def
_set_creditcourse
(
self
):
"""
Mark the course to credit
"""
# pylint: disable=attribute-defined-outside-init
self
.
first_provider
=
CreditProvider
.
objects
.
create
(
provider_id
=
"ASU"
,
display_name
=
"Arizona State University"
,
provider_url
=
"google.com"
,
enable_integration
=
True
)
# pylint: disable=attribute-defined-outside-init
self
.
second_provider
=
CreditProvider
.
objects
.
create
(
provider_id
=
"MIT"
,
display_name
=
"Massachusetts Institute of Technology"
,
provider_url
=
"MIT.com"
,
enable_integration
=
True
)
# pylint: disable=attribute-defined-outside-init
self
.
credit_course
=
CreditCourse
.
objects
.
create
(
course_key
=
self
.
course
.
id
,
enabled
=
True
)
# pylint: disable=attribute-defined-outside-init
self
.
credit_course
.
providers
.
add
(
self
.
first_provider
)
self
.
credit_course
.
providers
.
add
(
self
.
second_provider
)
def
_set_user_eligible
(
self
,
credit_course
,
username
):
"""
Mark the user eligible for credit for the given credit course.
"""
self
.
eligibility
=
CreditEligibility
.
objects
.
create
(
username
=
username
,
course
=
credit_course
)
# pylint: disable=attribute-defined-outside-init
def
test_user_request_status
(
self
):
request_status
=
api
.
get_credit_request_status
(
self
.
student
.
username
,
self
.
course
.
id
)
self
.
assertEqual
(
len
(
request_status
),
0
)
def
test_credit_messages
(
self
):
self
.
_set_creditcourse
()
requirement
=
CreditRequirement
.
objects
.
create
(
course
=
self
.
credit_course
,
namespace
=
"grade"
,
name
=
"grade"
,
active
=
True
)
status
=
CreditRequirementStatus
.
objects
.
create
(
username
=
self
.
student
.
username
,
requirement
=
requirement
,
)
status
.
status
=
"satisfied"
status
.
reason
=
{
"final_grade"
:
self
.
FINAL_GRADE
}
status
.
save
()
self
.
_set_user_eligible
(
self
.
credit_course
,
self
.
student
.
username
)
response
=
self
.
client
.
get
(
reverse
(
"dashboard"
))
self
.
assertContains
(
response
,
"<b>Congratulations</b> {}, You have meet requirements for credit."
.
format
(
self
.
student
.
get_full_name
()
# pylint: disable=no-member
)
)
api
.
create_credit_request
(
self
.
course
.
id
,
self
.
first_provider
.
provider_id
,
self
.
student
.
username
)
response
=
self
.
client
.
get
(
reverse
(
"dashboard"
))
self
.
assertContains
(
response
,
'Thank you, your payment is complete, your credit is processing. '
'Please see {provider_link} for more information.'
.
format
(
provider_link
=
'<a href="#" target="_blank">{provider_name}</a>'
.
format
(
provider_name
=
self
.
first_provider
.
display_name
)
)
)
def
test_query_counts
(
self
):
# This check the number of queries executed while rendering the
# credit message to display on the dashboard.
# - 1 query: Check the user's eligibility.
# - 1 query: Get the user credit requests.
self
.
_set_creditcourse
()
requirement
=
CreditRequirement
.
objects
.
create
(
course
=
self
.
credit_course
,
namespace
=
"grade"
,
name
=
"grade"
,
active
=
True
)
status
=
CreditRequirementStatus
.
objects
.
create
(
username
=
self
.
student
.
username
,
requirement
=
requirement
,
)
status
.
status
=
"satisfied"
status
.
reason
=
{
"final_grade"
:
self
.
FINAL_GRADE
}
status
.
save
()
with
self
.
assertNumQueries
(
2
):
enrollment_dict
=
{
unicode
(
self
.
course
.
id
):
self
.
course
}
_create_credit_availability_message
(
enrollment_dict
,
self
.
student
)
openedx/core/djangoapps/credit/tests/test_views.py
View file @
987889fc
...
...
@@ -99,7 +99,6 @@ class CreditProviderViewTests(UrlResetMixin, TestCase):
CreditEligibility
.
objects
.
create
(
username
=
self
.
USERNAME
,
course
=
credit_course
,
provider
=
credit_provider
,
)
def
test_credit_request_and_response
(
self
):
...
...
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