From 987889fc37d2b4716df9ed965db96957866da75f Mon Sep 17 00:00:00 2001 From: aamir-khan Date: Fri, 5 Jun 2015 19:13:38 +0500 Subject: [PATCH] ECOM-1524: Display credit availability on the dashboard --- common/djangoapps/student/views.py | 58 ++++++- lms/envs/common.py | 10 ++ lms/static/sass/multicourse/_dashboard.scss | 4 + lms/templates/dashboard.html | 3 +- .../dashboard/_dashboard_course_listing.html | 8 +- .../_dashboard_credit_information.html | 70 ++++++++ openedx/core/djangoapps/credit/api.py | 140 +++++++++++++++- ...o__del_field_crediteligibility_provider.py | 138 ++++++++++++++++ openedx/core/djangoapps/credit/models.py | 42 ++++- .../core/djangoapps/credit/tests/test_api.py | 152 ++++++++++++++++-- .../djangoapps/credit/tests/test_views.py | 1 - 11 files changed, 598 insertions(+), 28 deletions(-) create mode 100644 lms/templates/dashboard/_dashboard_credit_information.html create mode 100644 openedx/core/djangoapps/credit/migrations/0009_auto__del_field_crediteligibility_provider.py diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 5cc906ad23..58b6425eaf 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -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. diff --git a/lms/envs/common.py b/lms/envs/common.py index 1aa40c9cf5..33ffef2d45 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -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' } } diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index 5edbdb4864..5d4e3ca26c 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -531,6 +531,10 @@ padding: 0; } + .purchase_credit { + float: right; + } + .message { @extend %ui-depth1; border-radius: 3px; diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 3dc379fab6..821a1291f5 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -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): diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index bf44791adc..aa431bbf0b 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -1,4 +1,4 @@ -<%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 (