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

feat: Authorize with Service Account by batch #98

Closed
wants to merge 2 commits into from
Closed
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ build
MANIFEST
dist
*.egg-info
*.idea
31 changes: 19 additions & 12 deletions pycronofy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def sequenced_availability(self, sequence=(), available_periods=()):

:rtype: ``list``
"""
options = {}
options = dict()
options['sequence'] = self.map_availability_sequence(sequence)

self.translate_available_periods(available_periods)
Expand Down Expand Up @@ -568,26 +568,33 @@ def upsert_event(self, calendar_id, event):
self.request_handler.post(
endpoint='calendars/%s/events' % calendar_id, data=event)

def authorize_with_service_account(self, email, scope, callback_url, state=None):
def authorize_with_service_account(self, email=None, scope=None, callback_url=None, service_account_authorizations=None, state=None):
""" Attempts to authorize the email with impersonation from a service account

:param string email: the email address to impersonate
:param string callback_url: URL to callback with the OAuth code.
:param string scope: The scope of the privileges you want the eventual access_token to grant.
:param string, optional state: A value that will be returned to you unaltered along with the authorization request decision.
:param list, optional service_account_authorizations: Allows a batch of 1 to 50 access requests to be submitted at the same time.
:return: nothing
"""
params = {
'email': email,
'scope': scope,
'callback_url': callback_url
}

if state is not None:
params['state'] = state
if service_account_authorizations is not None:
params = {
"service_account_authorizations": service_account_authorizations
}
else:
params = {
'email': email,
'scope': scope,
'callback_url': callback_url
}

if state is not None:
params['state'] = state

self.request_handler.post(
endpoint="service_account_authorizations", data=params)
None

def real_time_scheduling(self, availability, oauth, event, target_calendars=(), minimum_notice=None, callback_url=None, redirect_urls=None):
"""Generates an real time scheduling link to start the OAuth process with
Expand All @@ -611,7 +618,7 @@ def real_time_scheduling(self, availability, oauth, event, target_calendars=(),
:param dict event: - A dict describing the event
:param list target_calendars: - An list of dics stating into which calendars
to insert the created event
:param dict :minimum_notice - A dict describing the minimum notice for a booking (Optional)
:param dict, optional minimum_notice: - A dict describing the minimum notice for a booking (Optional)
(DEPRECATED) :param string :callback_url - A String representing the URL Cronofy will notify
once a slot has been selected.
:param dict callback_url: - A dict containing redirect URLs for the end-user's journey
Expand Down Expand Up @@ -732,7 +739,7 @@ def real_time_sequencing(self, availability, oauth, event, target_calendars=(),
}

if availability:
options = {}
options = dict()
options['sequence'] = self.map_availability_sequence(availability.get('sequence', None))

if availability.get('available_periods', None):
Expand Down
72 changes: 69 additions & 3 deletions pycronofy/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import pytz
import responses
from functools import partial
from pycronofy import Client
from pycronofy import settings
from pycronofy.exceptions import PyCronofyRequestError
Expand Down Expand Up @@ -743,7 +744,7 @@ def test_user_auth_link(client):

@responses.activate
def test_authorize_with_service_account(client):
"""Test authorize_with_service_account with correct dat
"""Test authorize_with_service_account with correct data

:param Client client: Client instance with test data.
"""
Expand All @@ -755,15 +756,80 @@ def request_callback(request):
assert payload['state'] == "state example"
assert payload['callback_url'] == "http://www.example.com/callback"

return (202, {}, None)
return 202, {}, None

# Test with single service account authorization
responses.add_callback(
responses.POST,
'%s/v1/service_account_authorizations' % settings.API_BASE_URL,
callback=request_callback,
content_type='application/json',
)
client.authorize_with_service_account("[email protected]", "felines", "http://www.example.com/callback", state="state example")
client.authorize_with_service_account(
email="[email protected]",
scope="felines",
callback_url="http://www.example.com/callback",
state="state example"
)


@responses.activate
def test_authorize_with_service_account_batch(client):
"""Test authorize_with_service_account with correct data

:param Client client: Client instance with test data.
"""

def request_callback(request, email, scope, state, callback_url):
request_body = json.loads(request.body)

assert request_body['service_account_authorizations'] != []

service_account_authorizations = request_body['service_account_authorizations']
for payload in service_account_authorizations:
assert payload['email'] == email
assert payload['scope'] == scope
assert payload['state'] == state
assert payload['callback_url'] == callback_url

return 202, {}, None

# Test with multiple service account authorizations
payloads = [
{
'email': '[email protected]',
'scope': 'felines',
'state': 'state example',
'callback_url': 'http://www.example.com/callback'
},
{
'email': '[email protected]',
'scope': 'felines',
'state': 'state example',
'callback_url': 'http://www.example.com/callback'
},
{
'email': '[email protected]',
'scope': 'felines',
'state': 'state example',
'callback_url': 'http://www.example.com/callback'
}
]

for data in payloads:
responses.add_callback(
responses.POST,
'%s/v1/service_account_authorizations' % settings.API_BASE_URL,
callback=partial(
request_callback,
email=data['email'], scope=data['scope'], callback_url=data['callback_url'], state=data['state']
),
content_type='application/json',
)

client.authorize_with_service_account(
service_account_authorizations=payloads
)


@responses.activate
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ classifiers = [
[tool.setuptools.dynamic]
version = {attr = "pycronofy.__version__"}

[tool.pytest.ini_options]
pythonpath = [
"."
]

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"