diff --git a/.travis.yml b/.travis.yml index ff43d00..bdc42f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,18 @@ language: python matrix: include: - - python: 3.5 - dist: trusty - sudo: false - python: 3.6 dist: trusty sudo: false - python: 3.7 dist: xenial - sudo: true + sudo: false + - python: 3.8 + dist: xenial + sudo: false + - python: 3.9 + dist: xenial + sudo: false install: - python setup.py develop diff --git a/setup.py b/setup.py index e2c3351..ccd2f39 100644 --- a/setup.py +++ b/setup.py @@ -29,9 +29,10 @@ 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python', ] ) diff --git a/typeform/__init__.py b/typeform/__init__.py index 27afd66..34fe264 100644 --- a/typeform/__init__.py +++ b/typeform/__init__.py @@ -1,5 +1,6 @@ from .forms import Forms from .responses import Responses +from .webhooks import Webhooks from .client import Client __all__ = ['Typeform'] @@ -13,6 +14,7 @@ def __init__(self, token: str, headers: dict = {}): client = Client(token, headers=headers) self.__forms = Forms(client) self.__responses = Responses(client) + self.__webhooks = Webhooks(client) @property def forms(self) -> Forms: @@ -21,3 +23,7 @@ def forms(self) -> Forms: @property def responses(self) -> Responses: return self.__responses + + @property + def webhooks(self) -> Webhooks: + return self.__webhooks diff --git a/typeform/client.py b/typeform/client.py index 53d284c..5f7bd0a 100644 --- a/typeform/client.py +++ b/typeform/client.py @@ -39,7 +39,7 @@ def __validator(self, result: requests.Response) -> typing.Union[str, dict]: if type(body) is dict and body.get('code', None) is not None: raise Exception(body.get('description')) elif result.status_code >= 400: - raise Exception(' '.join([str(result.status_code),result.reason])) + raise Exception(' '.join([str(result.status_code), result.reason])) elif len(result.text) == 0: return 'OK' else: diff --git a/typeform/test/fixtures.py b/typeform/test/fixtures.py index 0a3f003..95b9af1 100644 --- a/typeform/test/fixtures.py +++ b/typeform/test/fixtures.py @@ -10,5 +10,5 @@ WORKSPACE = 'https://api.typeform.com/workspaces/hn3dNa' WORKSPACE_ID = WORKSPACE.split('/')[-1] -if MOCK and (not TOKEN or '[YOUR WORKSPACE ID]' in WORKSPACE): - raise Exception("You need to setup TOKEN and WORKSPACE in fixtures.py") \ No newline at end of file +if (not MOCK) and (not TOKEN or '[YOUR WORKSPACE ID]' in WORKSPACE): + raise Exception('You need to setup TOKEN and WORKSPACE in fixtures.py') diff --git a/typeform/test/test_forms.py b/typeform/test/test_forms.py index 68af9d2..ceb26d6 100644 --- a/typeform/test/test_forms.py +++ b/typeform/test/test_forms.py @@ -15,7 +15,7 @@ def setUp(self): form = self.forms.create(dict(title="Form's test form", workspace={'href': WORKSPACE})) self.formID = form.get('id') else: - self.formID = "MOCK-FORM-ID" + self.formID = 'MOCK-FORM-ID' def tearDown(self): if not MOCK: @@ -93,7 +93,7 @@ def test_forms_update_as_patch_updates_a_form(self): update as patch updates a form """ with requests_mock.mock(real_http=not MOCK) as m: - m.patch(API_BASE_URL+'/forms/'+self.formID, json="OK") + m.patch(API_BASE_URL+'/forms/'+self.formID, json='OK') result = self.forms.update(self.formID, patch=True, data=[ dict(op='replace', path='/title', value='forms_update_as_patch_updates_a_form')]) @@ -125,7 +125,7 @@ def test_forms_delete_removes_the_correct_uid_form(self): self.assertEqual(get_one_result.get('id'), self.formID) self.forms.delete(self.formID) m.get(API_BASE_URL + '/forms/{}'.format(self.formID), - json=dict(code="FORM_NOT_FOUND", description="Non existing form with uid {}".format(self.formID))) + json=dict(code='FORM_NOT_FOUND', description='Non existing form with uid {}'.format(self.formID))) try: self.forms.get(self.formID) except Exception as err: @@ -153,7 +153,10 @@ def test_forms_create_creates_a_new_form(self): m.post(API_BASE_URL + '/forms', json=dict(id=str(self.formID))) m.get(API_BASE_URL + '/forms/{}'.format(self.formID), json=dict(id=str(self.formID))) - create_result = self.forms.create(dict(title='forms_create_creates_a_new_form', workspace={'href': WORKSPACE})) + create_result = self.forms.create(dict( + title='forms_create_creates_a_new_form', + workspace={'href': WORKSPACE}, + )) formID = create_result.get('id') diff --git a/typeform/test/test_responses.py b/typeform/test/test_responses.py index c86b8cd..154b4f4 100644 --- a/typeform/test/test_responses.py +++ b/typeform/test/test_responses.py @@ -16,7 +16,7 @@ def setUp(self): form = self.forms.create((dict(title="Responses's test form", workspace={'href': WORKSPACE}))) self.formID = form.get('id') else: - self.formID = "MOCK-FORM-ID" + self.formID = 'MOCK-FORM-ID' def tearDown(self): if not MOCK: diff --git a/typeform/webhooks.py b/typeform/webhooks.py new file mode 100644 index 0000000..6a5055c --- /dev/null +++ b/typeform/webhooks.py @@ -0,0 +1,42 @@ +from .client import Client + + +class Webhooks: + """Typeform Webhooks API client""" + + def __init__(self, client: Client): + """Constructor for Typeform Webhooks class""" + self.__client = client + + def list(self, uid: str) -> dict: + """ + Returns form webhooks and date and time of form landing and submission. + """ + return self.__client.request('get', '/forms/%s/webhooks' % uid) + + def get(self, uid: str, tag: str) -> dict: + """ + Returns form webhooks and date and time of form landing and submission. + """ + return self.__client.request('get', '/forms/%s/webhooks/%s' % (uid, tag)) + + def create_update(self, uid: str, tag: str, data={}) -> dict: + """ + Create or update a webhook. + { + 'url': url, str + 'enabled': enabled, bool + 'secret': secret, str + 'verify_ssl': verify_ssl bool + } + """ + return self.__client.request( + 'put', '/forms/%s/webhooks/%s' % (uid, tag), data=data + ) + + def delete(self, uid: str, tag: str) -> str: + """ + Delete webhooks to a form. + Return a `str` based on success of deletion, `OK` on success, otherwise an error message. + """ + return self.__client.request('delete', '/forms/%s/webhooks/%s' % (uid, tag))