Commit 2717f228 by Renzo Lucioni

Merge pull request #11483 from edx/renzo/programs-task-fixes

Fixes for program certificate generation
parents 7ccca469 67f8b490
...@@ -1625,6 +1625,12 @@ REQUIRE_JS_PATH_OVERRIDES = [ ...@@ -1625,6 +1625,12 @@ REQUIRE_JS_PATH_OVERRIDES = [
] ]
################################# CELERY ###################################### ################################# CELERY ######################################
# Celery's task autodiscovery won't find tasks nested in a tasks package.
# Tasks are only registered when the module they are defined in is imported.
CELERY_IMPORTS = (
'openedx.core.djangoapps.programs.tasks.v1.tasks',
)
# Message configuration # Message configuration
CELERY_TASK_SERIALIZER = 'json' CELERY_TASK_SERIALIZER = 'json'
......
...@@ -8,3 +8,6 @@ if and only if the service is deployed in the Open edX installation. ...@@ -8,3 +8,6 @@ if and only if the service is deployed in the Open edX installation.
To ensure maximum separation of concerns, and a minimum of interdependencies, To ensure maximum separation of concerns, and a minimum of interdependencies,
this package should be kept small, thin, and stateless. this package should be kept small, thin, and stateless.
""" """
# Register signal handlers
from . import signals
...@@ -49,7 +49,7 @@ def get_completed_courses(student): ...@@ -49,7 +49,7 @@ def get_completed_courses(student):
""" """
all_certs = get_certificates_for_user(student.username) all_certs = get_certificates_for_user(student.username)
return [ return [
{'course_id': cert['course_key'], 'mode': cert['type']} {'course_id': unicode(cert['course_key']), 'mode': cert['type']}
for cert in all_certs for cert in all_certs
if is_passing_status(cert['status']) if is_passing_status(cert['status'])
] ]
...@@ -108,7 +108,11 @@ def award_program_certificate(client, username, program_id): ...@@ -108,7 +108,11 @@ def award_program_certificate(client, username, program_id):
None None
""" """
client.user_credentials.post({'program_id': program_id, 'username': username}) client.user_credentials.post({
'username': username,
'credential': {'program_id': program_id},
'attributes': []
})
@task(bind=True, ignore_result=True) @task(bind=True, ignore_result=True)
......
...@@ -109,7 +109,7 @@ class GetCompletedProgramsTestCase(TestCase): ...@@ -109,7 +109,7 @@ class GetCompletedProgramsTestCase(TestCase):
{'course_id': 'test-course-2', 'mode': 'prof-ed'}, {'course_id': 'test-course-2', 'mode': 'prof-ed'},
] ]
result = tasks.get_completed_programs(test_client, payload) result = tasks.get_completed_programs(test_client, payload)
self.assertEqual(httpretty.last_request().body, json.dumps({'completed_courses': payload})) self.assertEqual(json.loads(httpretty.last_request().body), {'completed_courses': payload})
self.assertEqual(result, [1, 2, 3]) self.assertEqual(result, [1, 2, 3])
...@@ -165,12 +165,20 @@ class AwardProgramCertificateTestCase(TestCase): ...@@ -165,12 +165,20 @@ class AwardProgramCertificateTestCase(TestCase):
""" """
test_username = 'test-username' test_username = 'test-username'
test_client = EdxRestApiClient('http://test-server', jwt='test-token') test_client = EdxRestApiClient('http://test-server', jwt='test-token')
httpretty.register_uri( httpretty.register_uri(
httpretty.POST, httpretty.POST,
'http://test-server/user_credentials/', 'http://test-server/user_credentials/',
) )
tasks.award_program_certificate(test_client, test_username, 123) tasks.award_program_certificate(test_client, test_username, 123)
self.assertEqual(httpretty.last_request().body, json.dumps({'program_id': 123, 'username': test_username}))
expected_body = {
'username': test_username,
'credential': {'program_id': 123},
'attributes': []
}
self.assertEqual(json.loads(httpretty.last_request().body), expected_body)
@ddt.ddt @ddt.ddt
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import calendar import calendar
import datetime import datetime
import ddt
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase from django.test import TestCase
...@@ -16,6 +17,7 @@ from student.models import anonymous_id_for_user ...@@ -16,6 +17,7 @@ from student.models import anonymous_id_for_user
from student.tests.factories import UserFactory, UserProfileFactory from student.tests.factories import UserFactory, UserProfileFactory
@ddt.ddt
class TestIdTokenGeneration(TestCase): class TestIdTokenGeneration(TestCase):
"""Tests covering ID token generation.""" """Tests covering ID token generation."""
client_name = 'edx-dummy-client' client_name = 'edx-dummy-client'
...@@ -24,15 +26,17 @@ class TestIdTokenGeneration(TestCase): ...@@ -24,15 +26,17 @@ class TestIdTokenGeneration(TestCase):
super(TestIdTokenGeneration, self).setUp() super(TestIdTokenGeneration, self).setUp()
self.oauth2_client = ClientFactory(name=self.client_name, client_type=CONFIDENTIAL) self.oauth2_client = ClientFactory(name=self.client_name, client_type=CONFIDENTIAL)
self.user = UserFactory()
# Create a profile for the user self.user = UserFactory.build()
self.user_profile = UserProfileFactory(user=self.user) self.user.save()
@override_settings(OAUTH_OIDC_ISSUER='test-issuer', OAUTH_ID_TOKEN_EXPIRATION=1) @override_settings(OAUTH_OIDC_ISSUER='test-issuer', OAUTH_ID_TOKEN_EXPIRATION=1)
@freezegun.freeze_time('2015-01-01 12:00:00') @freezegun.freeze_time('2015-01-01 12:00:00')
def test_get_id_token(self): @ddt.data(True, False)
def test_get_id_token(self, has_profile):
"""Verify that ID tokens are signed with the correct secret and generated with the correct claims.""" """Verify that ID tokens are signed with the correct secret and generated with the correct claims."""
full_name = UserProfileFactory(user=self.user).name if has_profile else None
token = get_id_token(self.user, self.client_name) token = get_id_token(self.user, self.client_name)
payload = jwt.decode( payload = jwt.decode(
...@@ -47,7 +51,7 @@ class TestIdTokenGeneration(TestCase): ...@@ -47,7 +51,7 @@ class TestIdTokenGeneration(TestCase):
expected_payload = { expected_payload = {
'preferred_username': self.user.username, 'preferred_username': self.user.username,
'name': self.user_profile.name, 'name': full_name,
'email': self.user.email, 'email': self.user.email,
'administrator': self.user.is_staff, 'administrator': self.user.is_staff,
'iss': settings.OAUTH_OIDC_ISSUER, 'iss': settings.OAUTH_OIDC_ISSUER,
......
...@@ -41,13 +41,18 @@ def get_id_token(user, client_name): ...@@ -41,13 +41,18 @@ def get_id_token(user, client_name):
except Client.DoesNotExist: except Client.DoesNotExist:
raise ImproperlyConfigured('OAuth2 Client with name [%s] does not exist' % client_name) raise ImproperlyConfigured('OAuth2 Client with name [%s] does not exist' % client_name)
user_profile = UserProfile.objects.get(user=user) try:
# Service users may not have user profiles.
full_name = UserProfile.objects.get(user=user).name
except UserProfile.DoesNotExist:
full_name = None
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
expires_in = getattr(settings, 'OAUTH_ID_TOKEN_EXPIRATION', 30) expires_in = getattr(settings, 'OAUTH_ID_TOKEN_EXPIRATION', 30)
payload = { payload = {
'preferred_username': user.username, 'preferred_username': user.username,
'name': user_profile.name, 'name': full_name,
'email': user.email, 'email': user.email,
'administrator': user.is_staff, 'administrator': user.is_staff,
'iss': settings.OAUTH_OIDC_ISSUER, 'iss': settings.OAUTH_OIDC_ISSUER,
......
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