-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add support for travelperk sdk (#92)
- Loading branch information
1 parent
3812a71
commit 92f59c6
Showing
9 changed files
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from travelperk.core.client import Travelperk | ||
|
||
__all__ = [ | ||
'Travelperk' | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from .invoice_profiles import InvoiceProfiles | ||
|
||
__all__ = [ | ||
'InvoiceProfiles' | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from typing import List, Dict | ||
import requests | ||
import json | ||
|
||
from travelperk.exceptions import * | ||
|
||
class ApiBase: | ||
"""The base class for all API classes.""" | ||
|
||
def __init__(self): | ||
self.__access_token = None | ||
self.__server_url = None | ||
|
||
def change_access_token(self, access_token): | ||
"""Change the old access token with the new one. | ||
Parameters: | ||
access_token (str): The new access token. | ||
""" | ||
self.__access_token = access_token | ||
|
||
def set_server_url(self, server_url): | ||
"""Set the server URL dynamically upon creating a connection | ||
Parameters: | ||
server_url(str): The current server URL | ||
""" | ||
self.__server_url = server_url | ||
|
||
def _get_request(self, object_type: str, api_url: str) -> List[Dict] or Dict: | ||
"""Create a HTTP GET request. | ||
Parameters: | ||
api_url (str): Url for the wanted API. | ||
Returns: | ||
A response from the request (dict). | ||
""" | ||
|
||
api_headers = { | ||
'Authorization': 'Bearer {0}'.format(self.__access_token), | ||
'Accept': 'application/json', | ||
'Api-Version': '1' | ||
} | ||
|
||
response = requests.get( | ||
'{0}{1}'.format(self.__server_url, api_url), | ||
headers=api_headers | ||
) | ||
if response.status_code == 200: | ||
result = json.loads(response.text) | ||
return result[object_type] | ||
|
||
elif response.status_code == 400: | ||
raise BadRequestError('Something wrong with the request body', response.text) | ||
|
||
elif response.status_code == 401: | ||
raise UnauthorizedClientError('Wrong client secret or/and refresh token', response.text) | ||
|
||
elif response.status_code == 404: | ||
raise NotFoundError('Client ID doesn\'t exist', response.text) | ||
|
||
elif response.status_code == 500: | ||
raise InternalServerError('Internal server error', response.text) | ||
|
||
else: | ||
raise TravelperkError('Error: {0}'.format(response.status_code), response.text) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
""" | ||
Travelperk Invoices | ||
""" | ||
from .api_base import ApiBase | ||
|
||
|
||
class InvoiceProfiles(ApiBase): | ||
"""Class for Invoice Profiles APIs.""" | ||
|
||
GET_INVOICE_PROFILES = '/profiles' | ||
|
||
def get_all(self): | ||
"""Get a list of the existing Invoice Profiles in the Organization. | ||
Returns: | ||
List with dicts in Invoice Profile schema. | ||
""" | ||
return self._get_request('profiles', InvoiceProfiles.GET_INVOICE_PROFILES) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
""" | ||
Travelperk Python Class | ||
""" | ||
import json | ||
import requests | ||
from future.moves.urllib.parse import urlencode | ||
|
||
from travelperk.exceptions import * | ||
from travelperk.apis.invoice_profiles import InvoiceProfiles | ||
|
||
class Travelperk: | ||
""" | ||
Travelperk Python Class | ||
""" | ||
|
||
def __init__(self, client_id: str, client_secret: str, | ||
refresh_token: str, environment: str): | ||
""" | ||
Initialize connection to Travelperk | ||
:param client_id: Travelperk client_Id | ||
:param client_secret: Travelperk client_secret | ||
:param refresh_token: Travelperk refresh_token | ||
:param environment: production or sandbox | ||
""" | ||
# Initializing variables | ||
self.__client_id = client_id | ||
self.__client_secret = client_secret | ||
self.refresh_token = refresh_token | ||
|
||
if environment.lower() == 'sandbox': | ||
self.__base_url = 'https://api.sandbox-travelperk.com' | ||
self.__token_url = 'https://app.sandbox-travelperk.com/accounts/oauth2/token/' | ||
elif environment.lower() == 'production': | ||
self.__base_url = 'https://api.travelperk.com' | ||
self.__token_url = 'https://app.travelperk.com/accounts/oauth2/token/' | ||
else: | ||
raise ValueError('environment can only be prodcution / sandbox') | ||
|
||
self.__access_token = None | ||
|
||
self.invoice_profiles = InvoiceProfiles() | ||
|
||
self.update_access_token() | ||
self.update_server_url() | ||
|
||
def update_server_url(self): | ||
""" | ||
Update the server url in all API objects. | ||
""" | ||
base_url = self.__base_url | ||
|
||
self.invoice_profiles.set_server_url(base_url) | ||
|
||
def update_access_token(self): | ||
""" | ||
Update the access token and change it in all API objects. | ||
""" | ||
self.__get_access_token() | ||
access_token = self.__access_token | ||
|
||
self.invoice_profiles.change_access_token(access_token) | ||
|
||
def __get_access_token(self): | ||
"""Get the access token using a HTTP post. | ||
Returns: | ||
A new access token. | ||
""" | ||
|
||
api_data = { | ||
'grant_type': 'refresh_token', | ||
'refresh_token': self.refresh_token, | ||
'client_id': self.__client_id, | ||
'client_secret': self.__client_secret | ||
} | ||
|
||
headers = { | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
} | ||
|
||
response = requests.post(url=self.__token_url, data=urlencode(api_data), headers=headers) | ||
if response.status_code == 200: | ||
auth = json.loads(response.text) | ||
self.__access_token = auth['access_token'] | ||
self.refresh_token = auth['refresh_token'] | ||
|
||
elif response.status_code == 400: | ||
raise BadRequestError('Something wrong with the request body', response.text) | ||
|
||
elif response.status_code == 401: | ||
raise UnauthorizedClientError('Wrong client secret or/and refresh token', response.text) | ||
|
||
elif response.status_code == 404: | ||
raise NotFoundError('Client ID doesn\'t exist', response.text) | ||
|
||
elif response.status_code == 500: | ||
raise InternalServerError('Internal server error', response.text) | ||
|
||
else: | ||
raise TravelperkError('Error: {0}'.format(response.status_code), response.text) |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
""" | ||
TravelPerk Exceptions | ||
""" | ||
|
||
|
||
class TravelperkError(Exception): | ||
"""The base exception class for Travelperk. | ||
Parameters: | ||
msg (str): Short description of the error. | ||
response: Error response from the API call. | ||
""" | ||
|
||
def __init__(self, msg, response=None): | ||
super(TravelperkError, self).__init__(msg) | ||
self.message = msg | ||
self.response = response | ||
|
||
def __str__(self): | ||
return repr(self.message) | ||
|
||
|
||
class UnauthorizedClientError(TravelperkError): | ||
"""Wrong client secret and/or refresh token, 401 error.""" | ||
|
||
|
||
class ForbiddenClientError(TravelperkError): | ||
"""The user has insufficient privilege, 403 error.""" | ||
|
||
|
||
class BadRequestError(TravelperkError): | ||
"""Some of the parameters are wrong, 400 error.""" | ||
|
||
|
||
class NotFoundError(TravelperkError): | ||
"""Not found the item from URL, 404 error.""" | ||
|
||
|
||
class InternalServerError(TravelperkError): | ||
"""The rest Travelperk errors, 500 error.""" | ||
|
||
|
||
class RateLimitError(TravelperkError): | ||
"""To many requests, 429 error.""" |