From d12faa2b85365693fe1933d0830b090cca868dd5 Mon Sep 17 00:00:00 2001 From: andrey-canon Date: Wed, 2 Aug 2023 17:16:17 -0500 Subject: [PATCH] feat: add certificates api client https://edunext.atlassian.net/browse/FUTUREX-478 --- eox_nelp/api_clients/certificates.py | 68 +++++++++++++++++++ .../api_clients/tests/tests_certificates.py | 65 ++++++++++++++++++ eox_nelp/settings/test.py | 3 + 3 files changed, 136 insertions(+) create mode 100644 eox_nelp/api_clients/certificates.py create mode 100644 eox_nelp/api_clients/tests/tests_certificates.py diff --git a/eox_nelp/api_clients/certificates.py b/eox_nelp/api_clients/certificates.py new file mode 100644 index 00000000..41c70337 --- /dev/null +++ b/eox_nelp/api_clients/certificates.py @@ -0,0 +1,68 @@ +"""Client module for external certificate's API integration. + +Classes: + ExternalCertificatesApiClient: Class to interact with NELP external certificates service. +""" +from django.conf import settings + +from eox_nelp.api_clients import AbstractApiClient + + +class ExternalCertificatesApiClient(AbstractApiClient): + """Allow to perform multiple external certificates operations.""" + + def __init__(self): + client_id = getattr(settings, "EXTERNAL_CERTIFICATES_API_CLIENT_ID") + client_secret = getattr(settings, "EXTERNAL_CERTIFICATES_API_CLIENT_SECRET") + + super().__init__(client_id, client_secret) + + @property + def base_url(self): + return getattr(settings, "EXTERNAL_CERTIFICATES_API_URL") + + def create_external_certificate(self, certificate_data): + """This will create an external certificate based on the input data, this data should have the + following keys: + + id : edx-platform certificate identifier. + created_at : when the certificate was created. + expiration_date : when the certificate expires. + grade : The associated grade with the certificate. + is_passing : Boolean value that represent if the user has passed the course. + user : Dictionary with the following data: + national_id: User National identifier. + englishs_name : User name in English. + arabic_name : User name in Arabic. + Args: + certificate_data: Information about a the certificate. + + Returns: + response: requests response as dictionary. + + Raise: + KeyError: This will be raised when the mandatory are excluded in the certificate data. + """ + path = "certificates" # This is not clear at all + user = certificate_data["user"] + payload = { + "reference_id": certificate_data["id"], + "date": { + "issuance": str(certificate_data["created_at"]), + "expiration": str(certificate_data["expiration_date"]), + }, + "individual": { + "name_en": user.get("english_name", ""), + "name_ar": user.get("arabic_name", ""), + "id": user["national_id"], + "id_type": "saudi", + }, + "group_code": "fail", # This is not clear + "certificate_type": "completion", # What types do we have ? + "metadata": { + "degree": certificate_data["grade"], + "FAIL": certificate_data["is_passing"], + } + } + + return self.make_post(path, payload) diff --git a/eox_nelp/api_clients/tests/tests_certificates.py b/eox_nelp/api_clients/tests/tests_certificates.py new file mode 100644 index 00000000..79d8e90f --- /dev/null +++ b/eox_nelp/api_clients/tests/tests_certificates.py @@ -0,0 +1,65 @@ +"""This file contains all the test for certificates api client file. + +Classes: + TestExternalCertificatesApiClient: Test for eox-nelp/api_clients/certificates.py. +""" +import unittest + +from django.utils import timezone +from mock import patch + +from eox_nelp.api_clients.certificates import ExternalCertificatesApiClient +from eox_nelp.api_clients.tests import BasicApiClientMixin + + +class TestExternalCertificatesApiClient(BasicApiClientMixin, unittest.TestCase): + """Tests ExternalCertificatesApiClient""" + + def setUp(self): + """Setup common conditions for every test case""" + self.api_class = ExternalCertificatesApiClient + + @patch.object(ExternalCertificatesApiClient, "make_post") + @patch.object(ExternalCertificatesApiClient, "_authenticate") + def test_create_certificate(self, auth_mock, post_mock): + """Test successful post request. + + Expected behavior: + - Response is the expected value + """ + auth_mock.return_value = {} + expected_value = { + "status": {"success": True, "message": "successful", "code": 1} + } + post_mock.return_value = expected_value + user = { + "national_id": "10224587", + "english_name": " Testing", + "arabic_name": "اختبارات", + } + data = { + "id": "124ABC", + "created_at": timezone.now(), + "expiration_date": timezone.now() + timezone.timedelta(days=365), + "grade": 10, + "is_passing": True, + "user": user, + } + api_client = self.api_class() + + response = api_client.create_external_certificate(data) + + self.assertDictEqual(response, expected_value) + + @patch.object(ExternalCertificatesApiClient, "_authenticate") + def test_failed_create_certificate(self, auth_mock): + """Test when the mandatory fields has not been sent. + + Expected behavior: + - Raise KeyError exception. + """ + auth_mock.return_value = {} + data = {} + api_client = ExternalCertificatesApiClient() + + self.assertRaises(KeyError, api_client.create_external_certificate, data) diff --git a/eox_nelp/settings/test.py b/eox_nelp/settings/test.py index e9f70859..0caf89d7 100644 --- a/eox_nelp/settings/test.py +++ b/eox_nelp/settings/test.py @@ -36,6 +36,9 @@ def plugin_settings(settings): # pylint: disable=function-redefined settings.FUTUREX_API_CLIENT_ID = 'my-test-client-id' settings.FUTUREX_API_CLIENT_SECRET = 'my-test-client-secret' settings.FUTUREX_NOTIFY_SUBSECTION_SUBJECT_MESSAGE = DEFAULT_FUTUREX_NOTIFY_SUBSECTION_SUBJECT_MESSAGE # noqa: F405 + settings.EXTERNAL_CERTIFICATES_API_URL = 'https://testing.com' + settings.EXTERNAL_CERTIFICATES_API_CLIENT_ID = 'my-test-client-id' + settings.EXTERNAL_CERTIFICATES_API_CLIENT_SECRET = 'my-test-client-secret' SETTINGS = SettingsClass()