Commit a154e7f1 by Awais

Adding the ecom api functionality for the credentials.

ECOM-2931
parent f3d000ec
...@@ -4,6 +4,7 @@ import datetime ...@@ -4,6 +4,7 @@ import datetime
import json import json
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from freezegun import freeze_time from freezegun import freeze_time
...@@ -99,3 +100,13 @@ class EdxRestApiClientTest(TestCase): ...@@ -99,3 +100,13 @@ class EdxRestApiClientTest(TestCase):
) )
actual_object = ecommerce_api_client(self.user).baskets(1).order.get() actual_object = ecommerce_api_client(self.user).baskets(1).order.get()
self.assertEqual(actual_object, {u"result": u"Préparatoire"}) self.assertEqual(actual_object, {u"result": u"Préparatoire"})
def test_client_with_user_without_profile(self):
"""
Verify client initialize successfully for users having no profile.
"""
worker = User.objects.create_user(username='test_worker', email='test@example.com')
api_client = ecommerce_api_client(worker)
self.assertEqual(api_client._store['session'].auth.__dict__['username'], worker.username) # pylint: disable=protected-access
self.assertIsNone(api_client._store['session'].auth.__dict__['full_name']) # pylint: disable=protected-access
...@@ -34,6 +34,17 @@ ...@@ -34,6 +34,17 @@
</p> </p>
<p> <p>
% if providers:
${_(u"Congratulations! You are eligible to receive course credit from {providers} for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format(
link_start=u'<a href="{dashboard_url}">'.format(
dashboard_url=dashboard_link
),
link_end=u'</a>',
platform_name=settings.PLATFORM_NAME,
providers=providers
)}
% else:
${_(u"Congratulations! You are eligible to receive course credit for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format( ${_(u"Congratulations! You are eligible to receive course credit for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format(
link_start=u'<a href="{dashboard_url}">'.format( link_start=u'<a href="{dashboard_url}">'.format(
dashboard_url=dashboard_link dashboard_url=dashboard_link
...@@ -41,6 +52,7 @@ ...@@ -41,6 +52,7 @@
link_end=u'</a>', link_end=u'</a>',
platform_name=settings.PLATFORM_NAME platform_name=settings.PLATFORM_NAME
)} )}
% endif
</p> </p>
<p> <p>
......
...@@ -5,7 +5,11 @@ ${_(u"Hi {name},").format(name=full_name)} ...@@ -5,7 +5,11 @@ ${_(u"Hi {name},").format(name=full_name)}
${_(u"Hi,")} ${_(u"Hi,")}
% endif % endif
${_(u"Congratulations! You are eligible to receive course credit for successfully completing your edX course!")} % if providers:
${_(u"Congratulations! You are eligible to receive course credit from {providers} for successfully completing your edX course!").format(providers=providers)}
% else:
${_(u"Congratulations! You are eligible to receive course credit for successfully completing your edX course!")}
% endif
${_(u"Click on the link below to get your credit now:")} ${_(u"Click on the link below to get your credit now:")}
......
...@@ -28,11 +28,13 @@ def is_commerce_service_configured(): ...@@ -28,11 +28,13 @@ def is_commerce_service_configured():
def ecommerce_api_client(user): def ecommerce_api_client(user):
""" Returns an E-Commerce API client setup with authentication for the specified user. """ """ Returns an E-Commerce API client setup with authentication for the specified user. """
return EdxRestApiClient(settings.ECOMMERCE_API_URL, return EdxRestApiClient(
settings.ECOMMERCE_API_URL,
settings.ECOMMERCE_API_SIGNING_KEY, settings.ECOMMERCE_API_SIGNING_KEY,
user.username, user.username,
user.profile.name, user.profile.name if hasattr(user, 'profile') else None,
user.email, user.email,
tracking_context=create_tracking_context(user), tracking_context=create_tracking_context(user),
issuer=settings.JWT_ISSUER, issuer=settings.JWT_ISSUER,
expires_in=settings.JWT_EXPIRATION) expires_in=settings.JWT_EXPIRATION
)
...@@ -3,7 +3,7 @@ Django admin page for credit eligibility ...@@ -3,7 +3,7 @@ Django admin page for credit eligibility
""" """
from ratelimitbackend import admin from ratelimitbackend import admin
from openedx.core.djangoapps.credit.models import ( from openedx.core.djangoapps.credit.models import (
CreditCourse, CreditProvider, CreditEligibility, CreditRequest CreditConfig, CreditCourse, CreditProvider, CreditEligibility, CreditRequest
) )
...@@ -51,3 +51,4 @@ admin.site.register(CreditCourse, CreditCourseAdmin) ...@@ -51,3 +51,4 @@ admin.site.register(CreditCourse, CreditCourseAdmin)
admin.site.register(CreditProvider, CreditProviderAdmin) admin.site.register(CreditProvider, CreditProviderAdmin)
admin.site.register(CreditEligibility, CreditEligibilityAdmin) admin.site.register(CreditEligibility, CreditEligibilityAdmin)
admin.site.register(CreditRequest, CreditRequestAdmin) admin.site.register(CreditRequest, CreditRequestAdmin)
admin.site.register(CreditConfig)
...@@ -21,10 +21,11 @@ from django.utils.translation import ugettext as _ ...@@ -21,10 +21,11 @@ from django.utils.translation import ugettext as _
from email.mime.image import MIMEImage from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from eventtracking import tracker from eventtracking import tracker
from edxmako.shortcuts import render_to_string from edxmako.shortcuts import render_to_string
from edxmako.template import Template from edxmako.template import Template
from microsite_configuration import microsite from microsite_configuration import microsite
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
from openedx.core.djangoapps.credit.models import CreditConfig, CreditProvider
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -67,6 +68,26 @@ def send_credit_notifications(username, course_key): ...@@ -67,6 +68,26 @@ def send_credit_notifications(username, course_key):
# strip enclosing angle brackets from 'logo_image' cache 'Content-ID' # strip enclosing angle brackets from 'logo_image' cache 'Content-ID'
logo_image_id = logo_image.get('Content-ID', '')[1:-1] logo_image_id = logo_image.get('Content-ID', '')[1:-1]
providers = get_credit_provider_display_names(course_key)
providers_string = None
if providers:
if len(providers) > 1:
if len(providers) > 2:
# Translators: The join of three or more university names. The first of these formatting strings
# represents a comma-separated list of names (e.g., MIT, Harvard, Dartmouth).
providers_string = _("{first_providers}, and {last_provider}").format(
first_providers=u", ".join(providers[:-1]),
last_provider=providers[-1]
)
else:
# Translators: The join of two university names (e.g., Harvard and MIT).
providers_string = _("{first_provider} and {second_provider}").format(
first_provider=providers[0],
second_provider=providers[1]
)
else:
providers_string = providers[0]
context = { context = {
'full_name': user.get_full_name(), 'full_name': user.get_full_name(),
'platform_name': settings.PLATFORM_NAME, 'platform_name': settings.PLATFORM_NAME,
...@@ -75,6 +96,7 @@ def send_credit_notifications(username, course_key): ...@@ -75,6 +96,7 @@ def send_credit_notifications(username, course_key):
'dashboard_link': dashboard_link, 'dashboard_link': dashboard_link,
'credit_course_link': credit_course_link, 'credit_course_link': credit_course_link,
'tracking_pixel': tracking_pixel, 'tracking_pixel': tracking_pixel,
'providers': providers_string,
} }
# create the root email message # create the root email message
...@@ -85,6 +107,10 @@ def send_credit_notifications(username, course_key): ...@@ -85,6 +107,10 @@ def send_credit_notifications(username, course_key):
notification_msg.attach(msg_alternative) notification_msg.attach(msg_alternative)
# render the credit notification templates # render the credit notification templates
subject = _(u'Course Credit Eligibility') subject = _(u'Course Credit Eligibility')
if providers:
subject = _(u'You are eligible for credit from {providers_string}').format(
providers_string=providers_string
)
# add alternative plain text message # add alternative plain text message
email_body_plain = render_to_string('credit_notifications/credit_eligibility_email.txt', context) email_body_plain = render_to_string('credit_notifications/credit_eligibility_email.txt', context)
...@@ -180,3 +206,56 @@ def _email_url_parser(url_name, extra_param=None): ...@@ -180,3 +206,56 @@ def _email_url_parser(url_name, extra_param=None):
dashboard_url_path = reverse(url_name) + extra_param if extra_param else reverse(url_name) dashboard_url_path = reverse(url_name) + extra_param if extra_param else reverse(url_name)
dashboard_link_parts = ("https", site_name, dashboard_url_path, '', '', '') dashboard_link_parts = ("https", site_name, dashboard_url_path, '', '', '')
return urlparse.urlunparse(dashboard_link_parts) return urlparse.urlunparse(dashboard_link_parts)
def get_credit_provider_display_names(course_key):
"""Get the course information from ecommerce and parse the data to get providers.
Arguments:
course_key (CourseKey): The identifier for the course.
Returns:
List of credit provider display names.
"""
course_id = unicode(course_key)
credit_config = CreditConfig.current()
cache_key = None
provider_names = None
if credit_config.is_cache_enabled:
cache_key = '{key_prefix}.{course_key}'.format(
key_prefix=credit_config.CACHE_KEY, course_key=course_id
)
provider_names = cache.get(cache_key)
if provider_names is not None:
return provider_names
try:
user = User.objects.get(username=settings.ECOMMERCE_SERVICE_WORKER_USERNAME)
response = ecommerce_api_client(user).courses(course_id).get(include_products=1)
except Exception: # pylint: disable=broad-except
log.exception("Failed to receive data from the ecommerce course API for Course ID '%s'.", course_id)
return provider_names
if not response:
log.info("No Course information found from ecommerce API for Course ID '%s'.", course_id)
return provider_names
provider_ids = []
for product in response.get('products'):
provider_ids += [
attr.get('value') for attr in product.get('attribute_values') if attr.get('name') == 'credit_provider'
]
provider_names = []
credit_providers = CreditProvider.get_credit_providers()
for provider in credit_providers:
if provider['id'] in provider_ids:
provider_names.append(provider['display_name'])
if credit_config.is_cache_enabled:
cache.set(cache_key, provider_names, credit_config.cache_ttl)
return provider_names
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('credit', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CreditConfig',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('cache_ttl', models.PositiveIntegerField(default=0, help_text='Specified in seconds. Enable caching by setting this to a value greater than 0.', verbose_name='Cache Time To Live')),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={
'ordering': ('-change_date',),
'abstract': False,
},
),
]
...@@ -6,23 +6,22 @@ Credit courses allow students to receive university credit for ...@@ -6,23 +6,22 @@ Credit courses allow students to receive university credit for
successful completion of a course on EdX successful completion of a course on EdX
""" """
import datetime
from collections import defaultdict from collections import defaultdict
import datetime
import logging import logging
import pytz from config_models.models import ConfigurationModel
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.dispatch import receiver
from django.db import models, transaction, IntegrityError
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from simple_history.models import HistoricalRecords from django.db import models, transaction, IntegrityError
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy, ugettext as _
from jsonfield.fields import JSONField from jsonfield.fields import JSONField
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
import pytz
from simple_history.models import HistoricalRecords
from xmodule_django.models import CourseKeyField from xmodule_django.models import CourseKeyField
from django.utils.translation import ugettext_lazy
CREDIT_PROVIDER_ID_REGEX = r"[a-z,A-Z,0-9,\-]+" CREDIT_PROVIDER_ID_REGEX = r"[a-z,A-Z,0-9,\-]+"
...@@ -709,3 +708,25 @@ class CreditRequest(TimeStampedModel): ...@@ -709,3 +708,25 @@ class CreditRequest(TimeStampedModel):
provider=self.provider.provider_id, provider=self.provider.provider_id,
status=self.status, status=self.status,
) )
class CreditConfig(ConfigurationModel):
""" Manage credit configuration """
CACHE_KEY = 'credit.providers.api.data'
cache_ttl = models.PositiveIntegerField(
verbose_name=_("Cache Time To Live"),
default=0,
help_text=_(
"Specified in seconds. Enable caching by setting this to a value greater than 0."
)
)
@property
def is_cache_enabled(self):
"""Whether responses from the commerce API will be cached."""
return self.enabled and self.cache_ttl > 0
def __unicode__(self):
"""Unicode representation of the config. """
return 'Credit Configuration'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment