From 30b1ca6c523c0778ca99d01651c34a8478aeda6c Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 11:18:58 +0530 Subject: [PATCH] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 36 +++++++++++++++++++++++ sendgrid/base_interface.py | 30 +++++++++++++++++-- sendgrid/sendgrid.py | 8 ++++-- test/unit/test_sendgrid.py | 43 ++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 examples/dataresidency/set_region.py create mode 100644 test/unit/test_sendgrid.py diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py new file mode 100644 index 000000000..e4cae4c98 --- /dev/null +++ b/examples/dataresidency/set_region.py @@ -0,0 +1,36 @@ +import sendgrid +import os + +from sendgrid import Email, To, Content, Mail + +# Example 1 +# setting region to be "global" +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) +sg.set_region("global") +from_email = Email("example@abc.com") +to_email = To("example@abc.com") +subject = "Sending with SendGrid is Fun" +content = Content("text/plain", "and easy to do anywhere, even with Python") +print(sg.host) +mail = Mail(from_email, to_email, subject, content) +response = sg.client.mail.send.post(request_body=mail.get()) +print(response) +print(response.status_code) +print(response.body) +print(response.headers) + +# Example 2 +# setting region to "eu" +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) +sg.set_region("eu") +from_email = Email("example@abc.com") +to_email = To("example@abc.com") +subject = "Sending with SendGrid is Fun" +content = Content("text/plain", "and easy to do anywhere, even with Python") +print(sg.host) +mail = Mail(from_email, to_email, subject, content) +response = sg.client.mail.send.post(request_body=mail.get()) +print(response) +print(response.status_code) +print(response.body) +print(response.headers) \ No newline at end of file diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 92b38247e..99e0eb780 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -2,7 +2,7 @@ class BaseInterface(object): - def __init__(self, auth, host, impersonate_subuser): + def __init__(self, auth, host, region, impersonate_subuser): """ Construct the Twilio SendGrid v3 API object. Note that the underlying client is being set up during initialization, @@ -19,10 +19,15 @@ def __init__(self, auth, host, impersonate_subuser): :type impersonate_subuser: string :param host: base URL for API calls :type host: string + :param region: To determine the region which can only be 'global' or 'eu' + :type region: string """ from . import __version__ self.auth = auth - self.host = host + if host is not None and region == 'global': + self.set_host(host) + else: + self.set_region(region) self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) @@ -60,3 +65,24 @@ def send(self, message): message = message.get() return self.client.mail.send.post(request_body=message) + + def set_host(self,host): + self.host = host + + def set_region(self,region): + """ + * Client libraries contain setters for specifying region/edge. + * This allows support global and eu regions only. This set will likely expand in the future. + * Global should be the default + * Global region means the message should be sent through: + * HTTP: api.sendgrid.com + * EU region means the message should be sent through: + * HTTP: api.eu.sendgrid.com + :param region: + :return: + """ + region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} + if region in region_host_dict.keys(): + self.host = region_host_dict[region] + else: + raise ValueError("region can only be \"eu\" or \"global\"") diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 912d8336e..9eb9ffad0 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -32,7 +32,8 @@ class SendGridAPIClient(BaseInterface): def __init__( self, api_key=None, - host='https://api.sendgrid.com', + host=None, + region='global', impersonate_subuser=None): """ Construct the Twilio SendGrid v3 API object. @@ -51,8 +52,11 @@ def __init__( :type impersonate_subuser: string :param host: base URL for API calls :type host: string + :param region: To determine the region which can only be 'global' or 'eu' + :type region: string """ self.api_key = api_key or os.environ.get('SENDGRID_API_KEY') auth = 'Bearer {}'.format(self.api_key) - super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser) + super(SendGridAPIClient, self).__init__(auth, host, region, impersonate_subuser) + diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py new file mode 100644 index 000000000..ac104564b --- /dev/null +++ b/test/unit/test_sendgrid.py @@ -0,0 +1,43 @@ +import unittest +import sendgrid + +class UnitTests(unittest.TestCase): + def test_host_with_no_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + self.assertEqual("https://api.sendgrid.com",sg.host) + + def test_host_with_eu_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("eu") + self.assertEqual("https://api.eu.sendgrid.com",sg.host) + + def test_host_with_global_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("global") + self.assertEqual("https://api.sendgrid.com",sg.host) + + def test_host_with_host_first_eu_region_second(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_host("https://sendgrid.com") + sg.set_region("eu") + self.assertEqual("https://api.eu.sendgrid.com",sg.host) + + def test_host_with_eu_first_host_second(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("eu") + sg.set_host("https://sendgrid.com") + self.assertEqual("https://sendgrid.com",sg.host) + + def test_host_using_constructor(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host='https://sendgrid.com') + self.assertEqual("https://sendgrid.com",sg.host) + + def test_with_region_is_none(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + with self.assertRaises(ValueError): + sg.set_region("") + + def test_with_region_is_none(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + with self.assertRaises(ValueError): + sg.set_region("abc") \ No newline at end of file