From 6e788d95b9cb5b96c1360d7574a3c426a045b27d Mon Sep 17 00:00:00 2001 From: Tasawer Date: Thu, 9 Jul 2015 17:39:48 +0500 Subject: [PATCH] new view added "get_provider_detail" for getting provider info with provider_id ECOM-1858 --- .../core/djangoapps/credit/api/eligibility.py | 13 ++- .../core/djangoapps/credit/api/provider.py | 72 +++++---------- openedx/core/djangoapps/credit/models.py | 39 ++++++--- .../core/djangoapps/credit/tests/test_api.py | 26 +++--- openedx/core/djangoapps/credit/urls.py | 21 ++++- openedx/core/djangoapps/credit/views.py | 87 ++++++++++++++++++- 6 files changed, 178 insertions(+), 80 deletions(-) diff --git a/openedx/core/djangoapps/credit/api/eligibility.py b/openedx/core/djangoapps/credit/api/eligibility.py index 9a64d69c44..349941b179 100644 --- a/openedx/core/djangoapps/credit/api/eligibility.py +++ b/openedx/core/djangoapps/credit/api/eligibility.py @@ -155,12 +155,14 @@ def is_user_eligible_for_credit(username, course_key): return CreditEligibility.is_user_eligible_for_credit(course_key, username) -def get_eligibilities_for_user(username): +def get_eligibilities_for_user(username, course_key=None): """ - Retrieve all courses for which the user is eligible for credit. + Retrieve all courses or particular course for which the user is eligible + for credit. Arguments: username (unicode): Identifier of the user. + course_key (unicode): Identifier of the course. Example: >>> get_eligibilities_for_user("ron") @@ -179,12 +181,17 @@ def get_eligibilities_for_user(username): Returns: list """ + eligibilities = CreditEligibility.get_user_eligibilities(username) + + if course_key: + eligibilities = eligibilities.filter(course_key=course_key) + return [ { "course_key": eligibility.course.course_key, "deadline": eligibility.deadline, } - for eligibility in CreditEligibility.get_user_eligibilities(username) + for eligibility in eligibilities ] diff --git a/openedx/core/djangoapps/credit/api/provider.py b/openedx/core/djangoapps/credit/api/provider.py index 6048424b36..9b6cd8532e 100644 --- a/openedx/core/djangoapps/credit/api/provider.py +++ b/openedx/core/djangoapps/credit/api/provider.py @@ -30,66 +30,38 @@ from util.date_utils import to_timestamp log = logging.getLogger(__name__) -def get_credit_providers(): - """ - Retrieve all available credit providers. +def get_credit_providers(providers_list=None): + """Retrieve all available credit providers or filter on given providers_list. - Example: - >>> get_credit_providers() - [ - { - "id": "hogwarts", - "display_name": "Hogwarts School of Witchcraft and Wizardry" - }, - ... - ] + Arguments: + providers_list (list of strings or None): contains list of ids of credit providers + or None. - Returns: list - """ - return CreditProvider.get_credit_providers() + Returns: + list of credit providers represented as dictionaries - -def get_credit_provider_info(provider_id): - """Retrieve the 'CreditProvider' model data against provided - credit provider. - - Args: - provider_id (str): The identifier for the credit provider - - Returns: 'CreditProvider' data dictionary - - Example Usage: - >>> get_credit_provider_info("hogwarts") - { - "provider_id": "hogwarts", - "display_name": "Hogwarts School of Witchcraft and Wizardry", - "provider_url": "https://credit.example.com/", - "provider_status_url": "https://credit.example.com/status/", - "provider_description: "A new model for the Witchcraft and Wizardry School System.", - "enable_integration": False, - "fulfillment_instructions": " + Response Values: + >>> get_credit_providers(['hogwarts']) + [ + { + "id": "hogwarts", + "name": "Hogwarts School of Witchcraft and Wizardry", + "url": "https://credit.example.com/", + "status_url": "https://credit.example.com/status/", + "description: "A new model for the Witchcraft and Wizardry School System.", + "enable_integration": false, + "fulfillment_instructions": "

In order to fulfill credit, Hogwarts School of Witchcraft and Wizardry requires learners to:

", - } - + }, + ... + ] """ - credit_provider = CreditProvider.get_credit_provider(provider_id=provider_id) - credit_provider_data = {} - if credit_provider: - credit_provider_data = { - "provider_id": credit_provider.provider_id, - "display_name": credit_provider.display_name, - "provider_url": credit_provider.provider_url, - "provider_status_url": credit_provider.provider_status_url, - "provider_description": credit_provider.provider_description, - "enable_integration": credit_provider.enable_integration, - "fulfillment_instructions": credit_provider.fulfillment_instructions - } - return credit_provider_data + return CreditProvider.get_credit_providers(providers_list=providers_list) @transaction.commit_on_success diff --git a/openedx/core/djangoapps/credit/models.py b/openedx/core/djangoapps/credit/models.py index dcbf44cb03..a9c936f63a 100644 --- a/openedx/core/djangoapps/credit/models.py +++ b/openedx/core/djangoapps/credit/models.py @@ -114,31 +114,50 @@ class CreditProvider(TimeStampedModel): CREDIT_PROVIDERS_CACHE_KEY = "credit.providers.list" @classmethod - def get_credit_providers(cls): + def get_credit_providers(cls, providers_list=None): """ - Retrieve a list of all credit providers, represented + Retrieve a list of all credit providers or filter on providers_list, represented as dictionaries. + + Arguments: + provider_list (list of strings or None): contains list of ids if required results + to be filtered, None for all providers. + + Returns: + list of providers represented as dictionaries. + """ - # Attempt to retrieve the credit provider list from the cache + # Attempt to retrieve the credit provider list from the cache if provider_list is None # The cache key is invalidated when the provider list is updated # (a post-save signal handler on the CreditProvider model) # This doesn't happen very often, so we would expect a *very* high # cache hit rate. - providers = cache.get(cls.CREDIT_PROVIDERS_CACHE_KEY) - # Cache miss: construct the provider list and save it in the cache - if providers is None: - providers = [ + credit_providers = cache.get(cls.CREDIT_PROVIDERS_CACHE_KEY) + if credit_providers is None: + # Cache miss: construct the provider list and save it in the cache + + credit_providers = CreditProvider.objects.filter(active=True) + + credit_providers = [ { "id": provider.provider_id, "display_name": provider.display_name, + "url": provider.provider_url, "status_url": provider.provider_status_url, + "description": provider.provider_description, + "enable_integration": provider.enable_integration, + "fulfillment_instructions": provider.fulfillment_instructions, } - for provider in CreditProvider.objects.filter(active=True) + for provider in credit_providers ] - cache.set(cls.CREDIT_PROVIDERS_CACHE_KEY, providers) - return providers + cache.set(cls.CREDIT_PROVIDERS_CACHE_KEY, credit_providers) + + if providers_list: + credit_providers = [provider for provider in credit_providers if provider['id'] in providers_list] + + return credit_providers @classmethod def get_credit_provider(cls, provider_id): diff --git a/openedx/core/djangoapps/credit/tests/test_api.py b/openedx/core/djangoapps/credit/tests/test_api.py index 467cc60e0e..40db25e66c 100644 --- a/openedx/core/djangoapps/credit/tests/test_api.py +++ b/openedx/core/djangoapps/credit/tests/test_api.py @@ -440,7 +440,11 @@ class CreditProviderIntegrationApiTests(CreditApiTestBase): { "id": self.PROVIDER_ID, "display_name": self.PROVIDER_NAME, + "url": self.PROVIDER_URL, "status_url": self.PROVIDER_STATUS_URL, + "description": self.PROVIDER_DESCRIPTION, + "enable_integration": self.ENABLE_INTEGRATION, + "fulfillment_instructions": self.FULFILLMENT_INSTRUCTIONS } ]) @@ -452,25 +456,25 @@ class CreditProviderIntegrationApiTests(CreditApiTestBase): result = api.get_credit_providers() self.assertEqual(result, []) - def test_get_credit_provider_details(self): + def test_get_credit_providers_details(self): """Test that credit api method 'test_get_credit_provider_details' returns dictionary data related to provided credit provider. """ - expected_result = { - "provider_id": self.PROVIDER_ID, + expected_result = [{ + "id": self.PROVIDER_ID, "display_name": self.PROVIDER_NAME, - "provider_url": self.PROVIDER_URL, - "provider_status_url": self.PROVIDER_STATUS_URL, - "provider_description": self.PROVIDER_DESCRIPTION, + "url": self.PROVIDER_URL, + "status_url": self.PROVIDER_STATUS_URL, + "description": self.PROVIDER_DESCRIPTION, "enable_integration": self.ENABLE_INTEGRATION, - "fulfillment_instructions": self.FULFILLMENT_INSTRUCTIONS - } - result = api.get_credit_provider_info(self.PROVIDER_ID) + "fulfillment_instructions": self.FULFILLMENT_INSTRUCTIONS, + }] + result = api.get_credit_providers([self.PROVIDER_ID]) self.assertEqual(result, expected_result) # now test that user gets empty dict for non existent credit provider - result = api.get_credit_provider_info('fake_provider_id') - self.assertEqual(result, {}) + result = api.get_credit_providers(['fake_provider_id']) + self.assertEqual(result, []) def test_credit_request(self): # Initiate a credit request diff --git a/openedx/core/djangoapps/credit/urls.py b/openedx/core/djangoapps/credit/urls.py index 7d7282c91d..1c02e9e916 100644 --- a/openedx/core/djangoapps/credit/urls.py +++ b/openedx/core/djangoapps/credit/urls.py @@ -3,20 +3,35 @@ URLs for the credit app. """ from django.conf.urls import patterns, url -from .views import create_credit_request, credit_provider_callback +from .views import create_credit_request, credit_provider_callback, get_providers_detail, get_eligibility_for_user + +PROVIDER_ID_PATTERN = r'(?P[^/]+)' urlpatterns = patterns( '', url( - r"^v1/provider/(?P[^/]+)/request/$", + r"^v1/providers/$", + get_providers_detail, + name="providers_detail" + ), + + url( + r"^v1/providers/{provider_id}/request/$".format(provider_id=PROVIDER_ID_PATTERN), create_credit_request, name="create_request" ), url( - r"^v1/provider/(?P[^/]+)/callback/?$", + r"^v1/providers/{provider_id}/callback/?$".format(provider_id=PROVIDER_ID_PATTERN), credit_provider_callback, name="provider_callback" ), + + url( + r"^v1/eligibility/$", + get_eligibility_for_user, + name="eligibility_details" + ), + ) diff --git a/openedx/core/djangoapps/credit/views.py b/openedx/core/djangoapps/credit/views.py index 9e4506f361..94ef0df283 100644 --- a/openedx/core/djangoapps/credit/views.py +++ b/openedx/core/djangoapps/credit/views.py @@ -12,7 +12,7 @@ from django.http import ( HttpResponseForbidden, Http404 ) -from django.views.decorators.http import require_POST +from django.views.decorators.http import require_POST, require_GET from django.views.decorators.csrf import csrf_exempt from django.conf import settings @@ -29,6 +29,54 @@ from openedx.core.djangoapps.credit.exceptions import CreditApiBadRequest, Credi log = logging.getLogger(__name__) +@require_GET +def get_providers_detail(request): + """ + + **User Cases** + + Returns details of the credit providers filtered by provided query parameters. + + **Parameters:** + + * provider_id (list of provider ids separated with ","): The identifiers for the providers for which + user requested + + **Example Usage:** + + GET /api/credit/v1/providers?provider_id=asu,hogwarts + "response": [ + "id": "hogwarts", + "display_name": "Hogwarts School of Witchcraft and Wizardry", + "url": "https://credit.example.com/", + "status_url": "https://credit.example.com/status/", + "description": "A new model for the Witchcraft and Wizardry School System.", + "enable_integration": false, + "fulfillment_instructions": " +

In order to fulfill credit, Hogwarts School of Witchcraft and Wizardry requires learners to:

+
    +
  • Sample instruction abc
  • +
  • Sample instruction xyz
  • +
", + }, + ... + ] + + **Responses:** + + * 200 OK: The request was created successfully. Returned content + is a JSON-encoded dictionary describing what the client should + send to the credit provider. + + * 404 Not Found: The provider does not exist. + + """ + provider_id = request.GET.get("provider_id", None) + providers_list = provider_id.split(",") if provider_id else None + providers = api.get_credit_providers(providers_list) + return JsonResponse(providers) + + @require_POST def create_credit_request(request, provider_id): """ @@ -44,7 +92,7 @@ def create_credit_request(request, provider_id): **Example Usage:** - POST /api/credit/v1/provider/hogwarts/request/ + POST /api/credit/v1/providers/hogwarts/request/ { "username": "ron", "course_key": "edX/DemoX/Demo_Course" @@ -136,7 +184,7 @@ def credit_provider_callback(request, provider_id): **Example Usage:** - POST /api/credit/v1/provider/{provider-id}/callback + POST /api/credit/v1/providers/{provider-id}/callback { "request_uuid": "557168d0f7664fe59097106c67c3f847", "status": "approved", @@ -200,6 +248,39 @@ def credit_provider_callback(request, provider_id): return HttpResponse() +@require_GET +def get_eligibility_for_user(request): + """ + + **User Cases** + + Retrieve user eligibility against course. + + **Parameters:** + + * course_key (unicode): Identifier of course. + * username (unicode): Username of current User. + + **Example Usage:** + + GET /api/credit/v1/eligibility?username=user&course_key=edX/Demo_101/Fall + "response": { + "course_key": "edX/Demo_101/Fall", + "deadline": "2015-10-23" + } + + **Responses:** + + * 200 OK: The request was created successfully. + + * 404 Not Found: The provider does not exist. + + """ + course_key = request.GET.get("course_key", None) + username = request.GET.get("username", None) + return JsonResponse(api.get_eligibilities_for_user(username=username, course_key=course_key)) + + def _validate_json_parameters(params_string, expected_parameters): """ Load the request parameters as a JSON dictionary and check that