Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: sms vendor with notification-gateway api #191

Merged
merged 2 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions eox_nelp/api_clients/authenticators.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,37 @@ def authenticate(self, api_client):
)

return session


class Oauth2BasicAuthenticator(BasicAuthAuthenticator):
"""Authenticator for custom use using basic auth to get a Oauth2 Token (Bearer or JWT).
Token_type on depends of the response used after the oauth2 token request.
Then the token is used for the next requests.
"""

def authenticate(self, api_client):
"""Authenticate the session with basic auth in order to get token(Bearer or JWT).
Then the token is added to a new session Headers.
Is needed the user, password and token_path class atrributes to the get oauth2 token,
based on the client configuration.
"""
auth_session = super().authenticate(api_client)
key = f"oauth2-basic-{api_client.user}-{api_client.password}"
headers = cache.get(key)

if not headers:
authenticate_url = f"{api_client.base_url}/{api_client.token_path}"
response = auth_session.post(
url=authenticate_url,
data={"grant_type": "client_credentials", "scope": "notification"}
).json()
headers = {
"Authorization": f"{response.get('token_type')} {response.get('access_token')}"
}

cache.set(key, headers, int(response.get("expires_in", 300)))

session = requests.Session()
session.headers.update(headers)

return session
16 changes: 11 additions & 5 deletions eox_nelp/api_clients/sms_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings

from eox_nelp.api_clients import AbstractAPIRestClient
from eox_nelp.api_clients.authenticators import Oauth2BasicAuthenticator

try:
from eox_audit_model.decorators import audit_method
Expand All @@ -17,11 +18,19 @@ def audit_method(action): # pylint: disable=unused-argument

class SMSVendorApiClient(AbstractAPIRestClient):
"""Allow to perform SMS send operations."""
authentication_class = Oauth2BasicAuthenticator

@property
def base_url(self):
return getattr(settings, "SMS_VENDOR_URL")

def __init__(self):
self.user = getattr(settings, "SMS_VENDOR_USERNAME")
self.password = getattr(settings, "SMS_VENDOR_PASSWORD")
self.token_path = getattr(settings, "SMS_VENDOR_TOKEN_PATH")

super().__init__()

def send_sms(self, recipient, message):
"""This send SMS using an external Vendor via API.

Expand All @@ -37,11 +46,8 @@ def send_sms_request(recipient, message):
"""This is a wrapper that allows to make audit-able the send_SMS method."""
path = getattr(settings, "SMS_VENDOR_SEND_SMS_PATH", "")
payload = {
"message": message,
"number": recipient,
"username": getattr(settings, "SMS_VENDOR_USERNAME"),
"password": getattr(settings, "SMS_VENDOR_PASSWORD"),
"sender": getattr(settings, "SMS_VENDOR_MSG_SENDER", "NELC"),
"sms_message": message,
"recipient_number": recipient,
}
return self.make_post(path, payload)

Expand Down
22 changes: 11 additions & 11 deletions eox_nelp/api_clients/tests/test_sms_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"""
import unittest

from django.conf import settings
from mock import patch
from mock import Mock, patch

from eox_nelp.api_clients.sms_vendor import SMSVendorApiClient
from eox_nelp.api_clients.tests.mixins import TestRestApiClientMixin
Expand All @@ -20,28 +19,29 @@ def setUp(self):
self.api_class = SMSVendorApiClient

@patch.object(SMSVendorApiClient, "make_post")
@patch.object(SMSVendorApiClient, "_authenticate", Mock())
def test_send_sms(self, post_mock):
"""Test successful post request.

Expected behavior:
- Response is the expected value
"""
expected_value = {
"message": "SMS sent =), waiting what would be this field.",
"responseCode": 200,
"message": "Operation completed successfully",
"transaction_id": "50693df-665d-47e1-affb-01076a83b9023427",
"recipient": "+573219990000",
"timestamp": "1720220972275"
}
post_mock.return_value = expected_value
recipient = 3219802890
recipient = "+573219990000"
message = "This is a message to test SMS integration."
api_client = self.api_class()
expected_payload = {
"message": message,
"number": recipient,
"username": settings.SMS_VENDOR_USERNAME,
"password": settings.SMS_VENDOR_PASSWORD,
"sender": settings.SMS_VENDOR_MSG_SENDER,
"sms_message": message,
"recipient_number": recipient,
}

response = api_client.send_sms(recipient, message)

self.assertDictEqual(response, expected_value)
post_mock.assert_called_once_with("", expected_payload)
post_mock.assert_called_once_with("sms/send", expected_payload)
3 changes: 2 additions & 1 deletion eox_nelp/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ def plugin_settings(settings): # pylint: disable=function-redefined
settings.SMS_VENDOR_URL = 'https://testing.com'
settings.SMS_VENDOR_USERNAME = 'test-user'
settings.SMS_VENDOR_PASSWORD = 'test-password'
settings.SMS_VENDOR_MSG_SENDER = 'Nelc-test'
settings.SMS_VENDOR_TOKEN_PATH = "oauth2/v1/token"
settings.SMS_VENDOR_SEND_SMS_PATH = 'sms/send'

settings.PEARSON_RTI_WSDL_URL = 'https://testing.com'
settings.PEARSON_RTI_CERT = '/openedx/certs/cert.p12'
Expand Down
Loading