diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6aac485..e3a10c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## [v2.0.0rc1] - WebForms API v1.1.0-1.0.4 - 2024-09-24
+### Changed
+- Added support for version v1.1.0-1.0.4 of the DocuSign WebForms API.
+- Updated the SDK release version.
+
+## Important Action Required
+- User needs to update the base URL in your codebase (if passing to SDK explicitly) and remove the /v1.1 component at the end of the URL for the SDK to work properly with this release.
+
## [v1.0.0] - WebForms API v1.1.0-1.0.2 - 2024-02-14
## Version 1.0.0 (Initial Release)
- Introducing the SDK based on the OpenAPI specification of DocuSign WebForms APIs.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..d7a1dc4
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+exclude test/*
diff --git a/README.md b/README.md
index edd0c0a..896098f 100644
--- a/README.md
+++ b/README.md
@@ -1,128 +1,127 @@
-# docusign-webforms
-The Web Forms API facilitates generating semantic HTML forms around everyday contracts.
-
-This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project:
-
-- API version: 1.1.0
-- Package version: 1.0.0
-- Build package: io.swagger.codegen.languages.PythonClientCodegen
-For more information, please visit [https://developers.docusign.com/](https://developers.docusign.com/)
-
-## Requirements.
-
-Python 2.7 and 3.4+
-
-## Installation & Usage
-### pip install
-
-If the python package is hosted on Github, you can install directly from Github
-
-```sh
-pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git
-```
-(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git`)
-
-Then import the package:
-```python
-import docusign_webforms
-```
-
-### Setuptools
-
-Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
-
-```sh
-python setup.py install --user
-```
-(or `sudo python setup.py install` to install the package for all users)
-
-Then import the package:
-```python
-import docusign_webforms
-```
-
-## Getting Started
-
-Please follow the [installation procedure](#installation--usage) and then run the following:
-
-```python
-from __future__ import print_function
-import time
-import docusign_webforms
-from docusign_webforms.rest import ApiException
-from pprint import pprint
-
-# Configure OAuth2 access token for authorization: docusignAccessCode
-configuration = docusign_webforms.Configuration()
-configuration.access_token = 'YOUR_ACCESS_TOKEN'
-
-# create an instance of the API class
-api_instance = docusign_webforms.FormInstanceManagementApi(docusign_webforms.ApiClient(configuration))
-account_id = 'account_id_example' # str | Account identifier in which the web form resides
-form_id = 'form_id_example' # str | Unique identifier for a web form entity that is consistent for it's lifetime
-create_instance_body = docusign_webforms.CreateInstanceRequestBody() # CreateInstanceRequestBody | Request body containing properties that will be used to create instance.
-
-try:
- # Creates an instance of the web form
- api_response = api_instance.create_instance(account_id, form_id, create_instance_body)
- pprint(api_response)
-except ApiException as e:
- print("Exception when calling FormInstanceManagementApi->create_instance: %s\n" % e)
-
-```
-
-## Documentation for API Endpoints
-
-All URIs are relative to *https://www.docusign.net/webforms/v1.1*
-
-Class | Method | HTTP request | Description
------------- | ------------- | ------------- | -------------
-*FormInstanceManagementApi* | [**create_instance**](docs/FormInstanceManagementApi.md#create_instance) | **POST** /accounts/{account_id}/forms/{form_id}/instances | Creates an instance of the web form
-*FormInstanceManagementApi* | [**get_instance**](docs/FormInstanceManagementApi.md#get_instance) | **GET** /accounts/{account_id}/forms/{form_id}/instances/{instance_id} | Get form instance
-*FormInstanceManagementApi* | [**list_instances**](docs/FormInstanceManagementApi.md#list_instances) | **GET** /accounts/{account_id}/forms/{form_id}/instances | List instances
-*FormInstanceManagementApi* | [**refresh_token**](docs/FormInstanceManagementApi.md#refresh_token) | **POST** /accounts/{account_id}/forms/{form_id}/instances/{instance_id}/refresh | Refreshes the instance token
-*FormManagementApi* | [**get_form**](docs/FormManagementApi.md#get_form) | **GET** /accounts/{account_id}/forms/{form_id} | Get Form
-*FormManagementApi* | [**list_forms**](docs/FormManagementApi.md#list_forms) | **GET** /accounts/{account_id}/forms | List Forms
-
-
-## Documentation For Models
-
- - [AuthenticationMethod](docs/AuthenticationMethod.md)
- - [CreateInstanceRequestBody](docs/CreateInstanceRequestBody.md)
- - [HttpError](docs/HttpError.md)
- - [HttpSuccess](docs/HttpSuccess.md)
- - [InstanceSource](docs/InstanceSource.md)
- - [InstanceStatus](docs/InstanceStatus.md)
- - [TemplateProperties](docs/TemplateProperties.md)
- - [WebForm](docs/WebForm.md)
- - [WebFormComponentType](docs/WebFormComponentType.md)
- - [WebFormContent](docs/WebFormContent.md)
- - [WebFormInstance](docs/WebFormInstance.md)
- - [WebFormInstanceEnvelopes](docs/WebFormInstanceEnvelopes.md)
- - [WebFormInstanceList](docs/WebFormInstanceList.md)
- - [WebFormInstanceMetadata](docs/WebFormInstanceMetadata.md)
- - [WebFormMetadata](docs/WebFormMetadata.md)
- - [WebFormProperties](docs/WebFormProperties.md)
- - [WebFormSource](docs/WebFormSource.md)
- - [WebFormState](docs/WebFormState.md)
- - [WebFormSummary](docs/WebFormSummary.md)
- - [WebFormSummaryList](docs/WebFormSummaryList.md)
- - [WebFormUserInfo](docs/WebFormUserInfo.md)
- - [WebFormValues](docs/WebFormValues.md)
-
-
-## Documentation For Authorization
-
-
-## docusignAccessCode
-
-- **Type**: OAuth
-- **Flow**: accessCode
-- **Authorization URL**: https://account.docusign.com/oauth/auth
-- **Scopes**: N/A
-
-
-## Author
-
-devcenter@docusign.com
-
+# The Official Docusign WebForms Python Client SDK
+
+[![PyPI version][pypi-image]][pypi-url]
+
+
+The Docusign SDK makes integrating Docusign into your apps and websites a seamless experience.
+
+## Table of Contents
+- [Introduction](#introduction)
+- [Installation](#installation)
+ * [Version Information](#versionInformation)
+ * [Requirements](#requirements)
+ * [Compatibility](#compatibility)
+ * [Path setup](#pathSetup)
+ * [Install via PIP](#pip)
+- [Dependencies](#dependencies)
+- [API Reference](#apiReference)
+- [Code Examples](#codeExamples)
+- [OAuth Implementations](#oauthImplementations)
+- [Changelog](#changeLog)
+- [Support](#support)
+- [License](#license)
+- [Additional Resources](#additionalResources)
+
+
+## Introduction
+Leverage the power of Web Forms in your agreement processes. Enjoy greater flexibility to manage forms using your own code including the creation and management of form instances with prefilled data. This API works with Docusign JS to enable the embedding of a web form instance in your web application.
+
+
+## Installation
+This client SDK is provided as open source, which enables you to customize its functionality to suit your particular use case. To do so, download or clone the repository. If the SDK’s given functionality meets your integration needs, or if you’re working through our [code examples](https://developers.docusign.com/docs/web-forms-api/how-to/) from the [Docusign Developer Center](https://developers.docusign.com/), you merely need to install it by following the instructions below.
+
+
+### Version Information
+- **API version**: 1.1.0
+- **Latest SDK version**: 2.0.0rc1
+
+
+## Requirements
+* Python 2.7 (3.7+ recommended)
+* Free [developer account](https://go.docusign.com/o/sandbox/?postActivateUrl=https://developers.docusign.com/)
+
+
+## Compatibility
+* Python 2.7+
+
+
+### Path setup:
+1. Locate your Python installation, also referred to as a **site-packages** folder. This folder is usually labeled in a format of **Python{VersionNumber}**.
+ **Examples:**
+ * Unix/Linux: **/usr/lib/python2.7**
+ * Mac: **/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7**
+ * Windows: **C:\Users\{username}\AppData\Local\Programs\Python\Python37**
+2. Add your Python folder’s path to your system as an environment variable.
+ **Unix/Linux:**
+ 1. Type the following command into your console: \
+ **export PYTHONPATH = "${PYTHONPATH}:.:/_path_/_to_/_site-packages_"**
+ 2. Optionally, you can add this command to your system profile, which will run the command each time Python is launched.
+
+ **Windows:**
+
+ - Open the Windows Control Panel.
+ - Under the System and Security category, open the System information panel.
+ - Select Advanced System Settings to open the System Properties dialog box.
+ - On the Advanced tab, select the Environment Variables button at the lower-right corner.
+
+ - Check to see whether PYTHONPATH has been added as a system variable.
+ - If it has not, select New to add it. The variable you add is the path to the site-packages folder.
+
+
+
+
+
+**Note:** If you are still unable to reference Python or pip via your command console, you can also add the path to the **site-packages** folder to the built-in environment variable labeled **Path**, which will take effect the next time you start your machine.
+
+
+### Install via PIP:
+In your command console, type: **pip install docusign_webforms**
+ **Note:** This may require the command console to be elevated. You can accomplish this via sudo in Unix/Linux, or by running the command console as an administrator in Windows.
+
+
+## SDK Dependencies
+This client has the following external dependencies:
+* certifi v14.05.14+
+* six v1.8.0+
+* python_dateutil v2.5.3+
+* setuptools v21.0.0+
+* urllib3 v1.15.1+
+* PyJWT v2.0.0+
+* cryptography v2.5+
+
+
+## API Reference
+You can refer to the API reference [here](https://developers.docusign.com/docs/web-forms-api/reference/).
+
+
+## Code examples
+Explore our GitHub repository for the [Launcher](https://github.com/docusign/code-examples-python/), a self-executing package housing code examples for the WebForms Python SDK. This package showcases several common use cases and their respective source files. Additionally, you can download a version preconfigured for your Docusign developer account from [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/). These examples support both the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) and [JSON Web Token (JWT)](https://developers.docusign.com/platform/auth/jwt/) authentication workflows.
+
+## OAuth implementations
+For details regarding which type of OAuth grant will work best for your Docusign integration, see [Choose OAuth Type](https://developers.docusign.com/platform/auth/choose/) in the [Docusign Developer Center](https://developers.docusign.com/).
+
+For security purposes, Docusign recommends using the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) flow.
+
+
+## Changelog
+You can refer to the complete changelog [here](https://github.com/docusign/docusign-webforms-python-client/blob/master/CHANGELOG.md).
+
+
+## Support
+Log issues against this client SDK through GitHub. You can also reach out to us through [Docusign Community](https://community.docusign.com/developer-59) and [Stack Overflow](https://stackoverflow.com/questions/tagged/docusignapi).
+
+
+## License
+The Docusign WebForms Python Client SDK is licensed under the [MIT License](https://github.com/docusign/docusign-webforms-python-client/blob/master/LICENSE).
+
+
+### Additional resources
+* [Docusign Developer Center](https://developers.docusign.com/)
+* [Docusign API on Twitter](https://twitter.com/docusignapi)
+* [Docusign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/)
+* [Docusign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2)
+
+[pypi-image]: https://img.shields.io/pypi/v/docusign_webforms.svg?style=flat
+[pypi-url]: https://pypi.python.org/pypi/docusign_webforms
+[downloads-image]: https://img.shields.io/pypi/dm/docusign_webforms.svg?style=flat
+[downloads-url]: https://pypi.python.org/pypi/docusign_webforms
\ No newline at end of file
diff --git a/docusign_webforms/__init__.py b/docusign_webforms/__init__.py
index e16601d..99e1e2a 100644
--- a/docusign_webforms/__init__.py
+++ b/docusign_webforms/__init__.py
@@ -51,6 +51,7 @@
from docusign_webforms.models.web_form_state import WebFormState
from docusign_webforms.models.web_form_summary import WebFormSummary
from docusign_webforms.models.web_form_summary_list import WebFormSummaryList
+from docusign_webforms.models.web_form_type import WebFormType
from docusign_webforms.models.web_form_user_info import WebFormUserInfo
from docusign_webforms.models.web_form_values import WebFormValues
diff --git a/docusign_webforms/apis/form_instance_management_api.py b/docusign_webforms/apis/form_instance_management_api.py
index 60a560c..4bf3689 100644
--- a/docusign_webforms/apis/form_instance_management_api.py
+++ b/docusign_webforms/apis/form_instance_management_api.py
@@ -118,12 +118,12 @@ def create_instance_with_http_info(self, account_id, form_id, create_instance_bo
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms/{form_id}/instances'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms/{formId}/instances'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
if 'form_id' in params:
- path_params['form_id'] = params['form_id']
+ path_params['formId'] = params['form_id']
query_params = {}
@@ -239,14 +239,14 @@ def get_instance_with_http_info(self, account_id, form_id, instance_id, **kwargs
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms/{form_id}/instances/{instance_id}'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms/{formId}/instances/{instanceId}'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
if 'form_id' in params:
- path_params['form_id'] = params['form_id']
+ path_params['formId'] = params['form_id']
if 'instance_id' in params:
- path_params['instance_id'] = params['instance_id']
+ path_params['instanceId'] = params['instance_id']
query_params = {}
@@ -359,12 +359,12 @@ def list_instances_with_http_info(self, account_id, form_id, **kwargs):
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms/{form_id}/instances'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms/{formId}/instances'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
if 'form_id' in params:
- path_params['form_id'] = params['form_id']
+ path_params['formId'] = params['form_id']
query_params = {}
if 'client_user_id' in params:
@@ -480,14 +480,14 @@ def refresh_token_with_http_info(self, account_id, form_id, instance_id, **kwarg
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms/{form_id}/instances/{instance_id}/refresh'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms/{formId}/instances/{instanceId}/refresh'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
if 'form_id' in params:
- path_params['form_id'] = params['form_id']
+ path_params['formId'] = params['form_id']
if 'instance_id' in params:
- path_params['instance_id'] = params['instance_id']
+ path_params['instanceId'] = params['instance_id']
query_params = {}
diff --git a/docusign_webforms/apis/form_management_api.py b/docusign_webforms/apis/form_management_api.py
index cafe079..a69bf6a 100644
--- a/docusign_webforms/apis/form_management_api.py
+++ b/docusign_webforms/apis/form_management_api.py
@@ -117,12 +117,12 @@ def get_form_with_http_info(self, account_id, form_id, **kwargs):
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms/{form_id}'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms/{formId}'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
if 'form_id' in params:
- path_params['form_id'] = params['form_id']
+ path_params['formId'] = params['form_id']
query_params = {}
if 'state' in params:
@@ -244,10 +244,10 @@ def list_forms_with_http_info(self, account_id, **kwargs):
collection_formats = {}
- resource_path = '/accounts/{account_id}/forms'.replace('{format}', 'json')
+ resource_path = '/v1.1/accounts/{accountId}/forms'.replace('{format}', 'json')
path_params = {}
if 'account_id' in params:
- path_params['account_id'] = params['account_id']
+ path_params['accountId'] = params['account_id']
query_params = {}
if 'user_filter' in params:
diff --git a/docusign_webforms/client/api_client.py b/docusign_webforms/client/api_client.py
index 66e7183..8edd6e6 100644
--- a/docusign_webforms/client/api_client.py
+++ b/docusign_webforms/client/api_client.py
@@ -17,7 +17,6 @@
import re
import json
import mimetypes
-import tempfile
import threading
import base64
import math
@@ -76,7 +75,7 @@ def __init__(self, host=None, header_name=None, header_value=None, cookie=None,
"""
config = Configuration()
- self.rest_client = RESTClientObject(config)
+ self.rest_client = RESTClientObject(configuration=config)
self.default_headers = {'X-DocuSign-SDK': 'Python'}
if header_name is not None:
self.default_headers[header_name] = header_value
@@ -178,9 +177,21 @@ def __call_api(self, resource_path, method,
return_data = response_data
if _preload_content:
r = RESTResponse(response_data)
+
# deserialize response data
if response_type:
- return_data = self.deserialize(r, response_type)
+ # In the python 3, the response.data is bytes.
+ # we need to decode it to string.
+ if PY3 and response_type != "file":
+ try:
+ r.data = r.data.decode('utf8', 'replace')
+ except (UnicodeDecodeError, AttributeError):
+ pass
+
+ if response_type == "file":
+ return_data = r.data
+ else:
+ return_data = self.deserialize(r, response_type)
else:
return_data = None
@@ -247,10 +258,9 @@ def deserialize(self, response, response_type):
:return: deserialized object.
"""
- # handle file downloading
- # save response body into a tmp file and return the instance
+ # handle file type response
if response_type == "file":
- return self.__deserialize_file(response)
+ return response.data
# fetch data from response object
try:
@@ -274,12 +284,12 @@ def __deserialize(self, data, klass):
if type(klass) == str:
if klass.startswith('list['):
- sub_kls = re.match('list\[(.*)\]', klass).group(1)
+ sub_kls = re.match(r'list\[(.*)\]', klass).group(1)
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
- sub_kls = re.match('dict\(([^,]*), (.*)\)', klass).group(2)
+ sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in iteritems(data)}
@@ -543,35 +553,6 @@ def update_params_for_auth(self, headers, querys, auth_settings):
'Authentication token must be in `query` or `header`'
)
- def __deserialize_file(self, response):
- """
- Saves response body into a file in a temporary folder,
- using the filename from the `Content-Disposition` header if provided.
-
- :param response: RESTResponse.
- :return: file path.
- """
- config = Configuration()
-
- fd, path = tempfile.mkstemp(dir=config.temp_folder_path)
- os.close(fd)
- os.remove(path)
-
- content_disposition = response.getheader("Content-Disposition")
- if content_disposition:
- filename = re.\
- search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).\
- group(1)
- curr_time = datetime.now()
- formatted_time = curr_time.strftime('%m%d%Y_%H%M%S_%f')
- filename = "{}_{}".format(formatted_time, filename)
- path = os.path.join(os.path.dirname(path), filename)
-
- with open(path, "wb") as f:
- f.write(response.data)
-
- return path
-
def __deserialize_primitive(self, data, klass):
"""
Deserializes string to primitive type.
@@ -663,9 +644,9 @@ def request_jwt_user_token(self, client_id, user_id, oauth_host_name, private_ke
scopes=(OAuth.SCOPE_SIGNATURE,)):
"""
Request JWT User Token
- :param client_id: DocuSign OAuth Client Id(AKA Integrator Key)
- :param user_id: DocuSign user Id to be impersonated
- :param oauth_host_name: DocuSign OAuth host name
+ :param client_id: Docusign OAuth Client Id(AKA Integrator Key)
+ :param user_id: Docusign user Id to be impersonated
+ :param oauth_host_name: Docusign OAuth host name
:param private_key_bytes: the byte contents of the RSA private key
:param expires_in: number of seconds remaining before the JWT assertion is considered as invalid
:param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any
@@ -706,8 +687,8 @@ def request_jwt_application_token(self, client_id, oauth_host_name, private_key_
scopes=(OAuth.SCOPE_SIGNATURE,)):
"""
Request JWT Application Token
- :param client_id: DocuSign OAuth Client Id(AKA Integrator Key)
- :param oauth_host_name: DocuSign OAuth host name
+ :param client_id: Docusign OAuth Client Id(AKA Integrator Key)
+ :param oauth_host_name: Docusign OAuth host name
:param private_key_bytes: the byte contents of the RSA private key
:param expires_in: number of seconds remaining before the JWT assertion is considered as invalid
:param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any
@@ -764,8 +745,8 @@ def get_user_info(self, access_token):
def generate_access_token(self, client_id, client_secret, code):
"""
GenerateAccessToken will exchange the authorization code for an access token and refresh tokens.
- :param client_id: DocuSign OAuth Client Id(AKA Integrator Key)
- :param client_secret: The secret key you generated when you set up the integration in DocuSign Admin console.
+ :param client_id: Docusign OAuth Client Id(AKA Integrator Key)
+ :param client_secret: The secret key you generated when you set up the integration in Docusign Admin console.
:param code: The authorization code
:return: OAuthToken object
"""
@@ -804,8 +785,6 @@ def set_oauth_host_name(self, oauth_host_name=None):
# Derive OAuth Base Path if not given
if self.base_path is None or self.base_path.startswith("https://demo") or self.base_path.startswith("http://demo") or self.base_path.startswith("https://apps-d") or self.base_path.startswith("http://apps-d"):
self.oauth_host_name = OAuth.DEMO_OAUTH_BASE_PATH
- elif self.base_path.startswith("https://stage") or self.base_path.startswith("http://stage") or self.base_path.startswith("https://apps-s") or self.base_path.startswith("http://apps-s"):
- self.oauth_host_name = OAuth.STAGE_OAUTH_BASE_PATH
else:
self.oauth_host_name = OAuth.PRODUCTION_OAUTH_BASE_PATH
@@ -820,7 +799,7 @@ def set_access_token(self, token_obj):
def get_authorization_uri(self, client_id, scopes, redirect_uri, response_type, state=None):
"""
Helper method to configure the OAuth accessCode/implicit flow parameters
- :param client_id: DocuSign OAuth Client Id(AKA Integrator Key)
+ :param client_id: Docusign OAuth Client Id(AKA Integrator Key)
:param scopes: The list of requested scopes. Client applications may be scoped to a limited set of system access.
:param redirect_uri: This determines where to deliver the response containing the authorization code
:param response_type: Determines the response type of the authorization request, NOTE: these response types are
diff --git a/docusign_webforms/client/api_exception.py b/docusign_webforms/client/api_exception.py
index a6eae67..4d4e283 100644
--- a/docusign_webforms/client/api_exception.py
+++ b/docusign_webforms/client/api_exception.py
@@ -51,9 +51,9 @@ class ArgumentException(Exception):
def __init__(self, *args, **kwargs):
if not args:
- super(Exception).__init__("argument cannot be empty")
+ super().__init__("argument cannot be empty")
else:
- super(Exception).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
class InvalidBasePath(Exception):
diff --git a/docusign_webforms/client/api_response.py b/docusign_webforms/client/api_response.py
index 01ad282..cb7e985 100644
--- a/docusign_webforms/client/api_response.py
+++ b/docusign_webforms/client/api_response.py
@@ -25,6 +25,7 @@
from six.moves.urllib.parse import urlencode
from .api_exception import ApiException
+from .configuration import Configuration
try:
import urllib3
@@ -54,13 +55,16 @@ def getheader(self, name, default=None):
class RESTClientObject(object):
- def __init__(self, configuration, pools_size=4, maxsize=None):
+ def __init__(self, pools_size=4, maxsize=None, configuration=None):
# urllib3.PoolManager will pass all kw parameters to connectionpool
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
# maxsize is the number of requests to host that are allowed in parallel # noqa: E501
# Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
+ if configuration is None:
+ configuration = Configuration()
+
# cert_reqs
if configuration.verify_ssl:
cert_reqs = ssl.CERT_REQUIRED
@@ -233,19 +237,12 @@ def request(self, method, url, query_params=None, headers=None,
msg = "{0}\n{1}".format(type(e).__name__, str(e))
raise ApiException(status=0, reason=msg)
- if _preload_content:
- r = RESTResponse(r)
-
- # In the python 3, the response.data is bytes.
- # we need to decode it to string.
- if six.PY3:
- try:
- r.data = r.data.decode('utf8')
- except (UnicodeDecodeError, AttributeError):
- pass
# log response body
logger.debug("response body: %s", r.data)
+ if _preload_content:
+ r = RESTResponse(r)
+
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
diff --git a/docusign_webforms/client/auth/oauth.py b/docusign_webforms/client/auth/oauth.py
index d75b501..ce776c8 100644
--- a/docusign_webforms/client/auth/oauth.py
+++ b/docusign_webforms/client/auth/oauth.py
@@ -33,8 +33,6 @@ class OAuth(object):
DEMO_OAUTH_BASE_PATH = "account-d.docusign.com"
# Production server base path
PRODUCTION_OAUTH_BASE_PATH = "account.docusign.com"
- # Stage server base path
- STAGE_OAUTH_BASE_PATH = "account-s.docusign.com"
# JWT Grant Type
GRANT_TYPE_JWT = "urn:ietf:params:oauth:grant-type:jwt-bearer"
diff --git a/docusign_webforms/client/configuration.py b/docusign_webforms/client/configuration.py
index 770bf87..547dc5c 100644
--- a/docusign_webforms/client/configuration.py
+++ b/docusign_webforms/client/configuration.py
@@ -50,14 +50,11 @@ def __init__(self):
return
# Default Base url
- self.host = "https://apps-d.docusign.com/api/webforms/v1.1"
+ self.host = "https://apps-d.docusign.com/api/webforms"
# Default api client
self.api_client = None
- # Temp file folder for downloading files
- self.temp_folder_path = None
-
# Authentication Settings
# dict to store API key(s)
self.api_key = {}
@@ -119,9 +116,9 @@ def __init__(self):
python_version = platform.python_version()
if six.PY3:
- self.user_agent = "Swagger-Codegen/1.1.0/1.0.0/python3/" + f"{python_version}"
+ self.user_agent = "Swagger-Codegen/1.1.0/2.0.0rc1/python3/" + f"{python_version}"
else:
- self.user_agent = "Swagger-Codegen/1.1.0/1.0.0/python2/" + f"{python_version}"
+ self.user_agent = "Swagger-Codegen/1.1.0/2.0.0rc1/python2/" + f"{python_version}"
@classmethod
@@ -277,5 +274,5 @@ def to_debug_report(self):
"OS: {env}\n"\
"Python Version: {pyversion}\n"\
"Version of the API: 1.1.0\n"\
- "SDK Package Version: 1.0.0".\
+ "SDK Package Version: 2.0.0rc1".\
format(env=sys.platform, pyversion=sys.version)
diff --git a/docusign_webforms/models/__init__.py b/docusign_webforms/models/__init__.py
index 5e9e258..58b8158 100644
--- a/docusign_webforms/models/__init__.py
+++ b/docusign_webforms/models/__init__.py
@@ -35,5 +35,6 @@
from docusign_webforms.models.web_form_state import WebFormState
from docusign_webforms.models.web_form_summary import WebFormSummary
from docusign_webforms.models.web_form_summary_list import WebFormSummaryList
+from docusign_webforms.models.web_form_type import WebFormType
from docusign_webforms.models.web_form_user_info import WebFormUserInfo
from docusign_webforms.models.web_form_values import WebFormValues
diff --git a/docusign_webforms/models/instance_source.py b/docusign_webforms/models/instance_source.py
index 9c4e5ae..184d5ed 100644
--- a/docusign_webforms/models/instance_source.py
+++ b/docusign_webforms/models/instance_source.py
@@ -32,6 +32,7 @@ class InstanceSource(object):
API_EMBEDDED = "API_EMBEDDED"
API_REMOTE = "API_REMOTE"
UI_REMOTE = "UI_REMOTE"
+ WORKFLOW = "WORKFLOW"
"""
Attributes:
diff --git a/docusign_webforms/models/instance_status.py b/docusign_webforms/models/instance_status.py
index c085d58..f14f109 100644
--- a/docusign_webforms/models/instance_status.py
+++ b/docusign_webforms/models/instance_status.py
@@ -29,6 +29,7 @@ class InstanceStatus(object):
allowed enum values
"""
INITIATED = "INITIATED"
+ IN_PROGRESS = "IN_PROGRESS"
SUBMITTED = "SUBMITTED"
EXPIRED = "EXPIRED"
FAILED = "FAILED"
diff --git a/docusign_webforms/models/web_form_metadata.py b/docusign_webforms/models/web_form_metadata.py
index ad50589..546f2e0 100644
--- a/docusign_webforms/models/web_form_metadata.py
+++ b/docusign_webforms/models/web_form_metadata.py
@@ -34,6 +34,8 @@ class WebFormMetadata(object):
"""
swagger_types = {
'source': 'WebFormSource',
+ 'type': 'WebFormType',
+ 'source_form_id': 'str',
'owner': 'WebFormUserInfo',
'sender': 'WebFormUserInfo',
'last_modified_by': 'WebFormUserInfo',
@@ -57,6 +59,8 @@ class WebFormMetadata(object):
attribute_map = {
'source': 'source',
+ 'type': 'type',
+ 'source_form_id': 'sourceFormId',
'owner': 'owner',
'sender': 'sender',
'last_modified_by': 'lastModifiedBy',
@@ -85,6 +89,8 @@ def __init__(self, _configuration=None, **kwargs): # noqa: E501
self._configuration = _configuration
self._source = None
+ self._type = None
+ self._source_form_id = None
self._owner = None
self._sender = None
self._last_modified_by = None
@@ -107,6 +113,8 @@ def __init__(self, _configuration=None, **kwargs): # noqa: E501
self.discriminator = None
setattr(self, "_{}".format('source'), kwargs.get('source', None))
+ setattr(self, "_{}".format('type'), kwargs.get('type', None))
+ setattr(self, "_{}".format('source_form_id'), kwargs.get('source_form_id', None))
setattr(self, "_{}".format('owner'), kwargs.get('owner', None))
setattr(self, "_{}".format('sender'), kwargs.get('sender', None))
setattr(self, "_{}".format('last_modified_by'), kwargs.get('last_modified_by', None))
@@ -131,7 +139,7 @@ def __init__(self, _configuration=None, **kwargs): # noqa: E501
def source(self):
"""Gets the source of this WebFormMetadata. # noqa: E501
- The source from which the webform is created. Accepted values are [upload, templates, blank] # noqa: E501
+ The source from which the webform is created. Accepted values are [templates, blank, form] # noqa: E501
:return: The source of this WebFormMetadata. # noqa: E501
:rtype: WebFormSource
@@ -142,7 +150,7 @@ def source(self):
def source(self, source):
"""Sets the source of this WebFormMetadata.
- The source from which the webform is created. Accepted values are [upload, templates, blank] # noqa: E501
+ The source from which the webform is created. Accepted values are [templates, blank, form] # noqa: E501
:param source: The source of this WebFormMetadata. # noqa: E501
:type: WebFormSource
@@ -150,6 +158,52 @@ def source(self, source):
self._source = source
+ @property
+ def type(self):
+ """Gets the type of this WebFormMetadata. # noqa: E501
+
+ Represents webform type. Possible values are [standalone, hasEsignTemplate] # noqa: E501
+
+ :return: The type of this WebFormMetadata. # noqa: E501
+ :rtype: WebFormType
+ """
+ return self._type
+
+ @type.setter
+ def type(self, type):
+ """Sets the type of this WebFormMetadata.
+
+ Represents webform type. Possible values are [standalone, hasEsignTemplate] # noqa: E501
+
+ :param type: The type of this WebFormMetadata. # noqa: E501
+ :type: WebFormType
+ """
+
+ self._type = type
+
+ @property
+ def source_form_id(self):
+ """Gets the source_form_id of this WebFormMetadata. # noqa: E501
+
+ The source form id from which the webform is created. # noqa: E501
+
+ :return: The source_form_id of this WebFormMetadata. # noqa: E501
+ :rtype: str
+ """
+ return self._source_form_id
+
+ @source_form_id.setter
+ def source_form_id(self, source_form_id):
+ """Sets the source_form_id of this WebFormMetadata.
+
+ The source form id from which the webform is created. # noqa: E501
+
+ :param source_form_id: The source_form_id of this WebFormMetadata. # noqa: E501
+ :type: str
+ """
+
+ self._source_form_id = source_form_id
+
@property
def owner(self):
"""Gets the owner of this WebFormMetadata. # noqa: E501
diff --git a/docusign_webforms/models/web_form_source.py b/docusign_webforms/models/web_form_source.py
index 7ae6e0a..80b87bc 100644
--- a/docusign_webforms/models/web_form_source.py
+++ b/docusign_webforms/models/web_form_source.py
@@ -30,6 +30,7 @@ class WebFormSource(object):
"""
TEMPLATES = "templates"
BLANK = "blank"
+ FORM = "form"
"""
Attributes:
diff --git a/docusign_webforms/models/web_form_summary.py b/docusign_webforms/models/web_form_summary.py
index dace836..89df510 100644
--- a/docusign_webforms/models/web_form_summary.py
+++ b/docusign_webforms/models/web_form_summary.py
@@ -37,6 +37,7 @@ class WebFormSummary(object):
'account_id': 'str',
'is_published': 'bool',
'is_enabled': 'bool',
+ 'is_uploaded': 'bool',
'has_draft_changes': 'bool',
'form_state': 'WebFormState',
'form_properties': 'WebFormProperties',
@@ -48,6 +49,7 @@ class WebFormSummary(object):
'account_id': 'accountId',
'is_published': 'isPublished',
'is_enabled': 'isEnabled',
+ 'is_uploaded': 'isUploaded',
'has_draft_changes': 'hasDraftChanges',
'form_state': 'formState',
'form_properties': 'formProperties',
@@ -64,6 +66,7 @@ def __init__(self, _configuration=None, **kwargs): # noqa: E501
self._account_id = None
self._is_published = None
self._is_enabled = None
+ self._is_uploaded = None
self._has_draft_changes = None
self._form_state = None
self._form_properties = None
@@ -74,6 +77,7 @@ def __init__(self, _configuration=None, **kwargs): # noqa: E501
setattr(self, "_{}".format('account_id'), kwargs.get('account_id', None))
setattr(self, "_{}".format('is_published'), kwargs.get('is_published', None))
setattr(self, "_{}".format('is_enabled'), kwargs.get('is_enabled', None))
+ setattr(self, "_{}".format('is_uploaded'), kwargs.get('is_uploaded', None))
setattr(self, "_{}".format('has_draft_changes'), kwargs.get('has_draft_changes', None))
setattr(self, "_{}".format('form_state'), kwargs.get('form_state', None))
setattr(self, "_{}".format('form_properties'), kwargs.get('form_properties', None))
@@ -167,6 +171,29 @@ def is_enabled(self, is_enabled):
self._is_enabled = is_enabled
+ @property
+ def is_uploaded(self):
+ """Gets the is_uploaded of this WebFormSummary. # noqa: E501
+
+ Has the form created through upload # noqa: E501
+
+ :return: The is_uploaded of this WebFormSummary. # noqa: E501
+ :rtype: bool
+ """
+ return self._is_uploaded
+
+ @is_uploaded.setter
+ def is_uploaded(self, is_uploaded):
+ """Sets the is_uploaded of this WebFormSummary.
+
+ Has the form created through upload # noqa: E501
+
+ :param is_uploaded: The is_uploaded of this WebFormSummary. # noqa: E501
+ :type: bool
+ """
+
+ self._is_uploaded = is_uploaded
+
@property
def has_draft_changes(self):
"""Gets the has_draft_changes of this WebFormSummary. # noqa: E501
diff --git a/docusign_webforms/models/web_form_type.py b/docusign_webforms/models/web_form_type.py
new file mode 100644
index 0000000..0d079ff
--- /dev/null
+++ b/docusign_webforms/models/web_form_type.py
@@ -0,0 +1,101 @@
+# coding: utf-8
+
+"""
+ Web Forms API version 1.1
+
+ The Web Forms API facilitates generating semantic HTML forms around everyday contracts. # noqa: E501
+
+ OpenAPI spec version: 1.1.0
+ Contact: devcenter@docusign.com
+ Generated by: https://github.com/swagger-api/swagger-codegen.git
+"""
+
+
+import pprint
+import re # noqa: F401
+
+import six
+
+from docusign_webforms.client.configuration import Configuration
+
+
+class WebFormType(object):
+ """NOTE: This class is auto generated by the swagger code generator program.
+
+ Do not edit the class manually.
+ """
+
+ """
+ allowed enum values
+ """
+ STANDALONE = "standalone"
+ HASESIGNTEMPLATE = "hasEsignTemplate"
+
+ """
+ Attributes:
+ swagger_types (dict): The key is attribute name
+ and the value is attribute type.
+ attribute_map (dict): The key is attribute name
+ and the value is json key in definition.
+ """
+ swagger_types = {
+ }
+
+ attribute_map = {
+ }
+
+ def __init__(self, _configuration=None, **kwargs): # noqa: E501
+ """WebFormType - a model defined in Swagger""" # noqa: E501
+ if _configuration is None:
+ _configuration = Configuration()
+ self._configuration = _configuration
+ self.discriminator = None
+
+ def to_dict(self):
+ """Returns the model properties as a dict"""
+ result = {}
+
+ for attr, _ in six.iteritems(self.swagger_types):
+ value = getattr(self, attr)
+ if isinstance(value, list):
+ result[attr] = list(map(
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
+ value
+ ))
+ elif hasattr(value, "to_dict"):
+ result[attr] = value.to_dict()
+ elif isinstance(value, dict):
+ result[attr] = dict(map(
+ lambda item: (item[0], item[1].to_dict())
+ if hasattr(item[1], "to_dict") else item,
+ value.items()
+ ))
+ else:
+ result[attr] = value
+ if issubclass(WebFormType, dict):
+ for key, value in self.items():
+ result[key] = value
+
+ return result
+
+ def to_str(self):
+ """Returns the string representation of the model"""
+ return pprint.pformat(self.to_dict())
+
+ def __repr__(self):
+ """For `print` and `pprint`"""
+ return self.to_str()
+
+ def __eq__(self, other):
+ """Returns true if both objects are equal"""
+ if not isinstance(other, WebFormType):
+ return False
+
+ return self.to_dict() == other.to_dict()
+
+ def __ne__(self, other):
+ """Returns true if both objects are not equal"""
+ if not isinstance(other, WebFormType):
+ return True
+
+ return self.to_dict() != other.to_dict()
diff --git a/requirements.txt b/requirements.txt
index 57db7c4..f90469a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,4 +5,3 @@ setuptools >= 21.0.0
urllib3 >= 1.15
PyJWT>=2.0.0
cryptography>=2.5
-nose>=1.3.7
diff --git a/setup.py b/setup.py
index e93bb5b..491e1dc 100644
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@
from setuptools import setup, find_packages, Command, os # noqa: H301
NAME = "docusign-webforms"
-VERSION = "1.0.0"
+VERSION = "2.0.0rc1"
# To install the library, run the following
#
# python setup.py install
@@ -22,7 +22,7 @@
# prerequisite: setuptools
# http://pypi.python.org/pypi/setuptools
-REQUIRES = ["urllib3 >= 1.15", "six >= 1.8.0", "certifi >= 14.05.14", "python-dateutil >= 2.5.3", "setuptools >= 21.0.0", "PyJWT>=2.0.0", "cryptography>=2.5", "nose>=1.3.7"]
+REQUIRES = ["urllib3 >= 1.15", "six >= 1.8.0", "certifi >= 14.05.14", "python-dateutil >= 2.5.3", "setuptools >= 21.0.0", "PyJWT>=2.0.0", "cryptography>=2.5"]
class CleanCommand(Command):
"""Custom clean command to tidy up the project root."""
@@ -47,7 +47,7 @@ def run(self):
url="",
keywords=["Swagger", "Web Forms API version 1.1"],
install_requires=REQUIRES,
- packages=find_packages(),
+ packages=find_packages(exclude=["test"]),
include_package_data=True,
cmdclass={
'clean': CleanCommand,
diff --git a/test-requirements.txt b/test-requirements.txt
index 4229be9..bb6d59b 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,5 +1,5 @@
coverage>=4.0.3
-nose>=1.3.7
+pynose>=1.4.8
pluggy>=0.3.1
py>=1.4.31
randomize>=0.13
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/__init__.py
@@ -0,0 +1 @@
+
diff --git a/test/test_form_instance_management_api.py b/test/test_form_instance_management_api.py
new file mode 100644
index 0000000..c2ad8e8
--- /dev/null
+++ b/test/test_form_instance_management_api.py
@@ -0,0 +1,229 @@
+from __future__ import absolute_import, print_function
+
+import unittest
+
+import docusign_webforms as docusign
+from docusign_webforms import ApiException, FormManagementApi, FormInstanceManagementApi
+from docusign_webforms.models import WebFormValues, CreateInstanceRequestBody
+from docusign_webforms.models.authentication_method import AuthenticationMethod
+from test.test_helper import TestHelper
+
+
+class FormInstanceManagementAPIUnitTests(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls._testConfig = TestHelper()
+ cls._api_client = cls._testConfig.get_authenticated_api_client()
+
+ cls._form_management_api = FormManagementApi(cls._api_client)
+ cls._form_instance_management_api = FormInstanceManagementApi(cls._api_client)
+ cls._published_form_id = None
+ cls._web_form_instance = None
+ cls._web_form_instance_id = None
+ cls._fill_dependencies()
+
+ @classmethod
+ def _fill_dependencies(cls):
+
+ try:
+ if cls._testConfig.published_webform_id is None:
+ webforms_list_data = cls._form_management_api.list_forms(cls._testConfig.account_id, is_published=True)
+ published_web_forms = [x for x in webforms_list_data.items if x.is_published]
+ if published_web_forms:
+ cls._published_form_id = published_web_forms[0].id
+ else:
+ cls._published_form_id = cls._testConfig.published_webform_id
+
+ # Get Instance ID
+ cls._web_form_instance = cls._create_webform_instance()
+ cls._web_form_instance_id = cls._web_form_instance.id
+ except ApiException as e:
+ print("\nApiException when setting up Dependencies Info: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+ except Exception as e:
+ print("\nException when setting up Dependencies Info: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+
+ @classmethod
+ def _get_webform_instance_create_request_body(cls):
+ values = ({
+ "Signer_name": "SDK Python Client - " + docusign.configuration.user_agent,
+ "Signer_email": "customer@domain.com",
+ "T1": "Customer"
+ })
+
+ requestBody = CreateInstanceRequestBody(
+ form_values=values,
+ client_user_id="customer_id@domain.com",
+ authentication_instant="02/02/2023",
+ authentication_method=AuthenticationMethod.BIOMETRIC,
+ assertion_id="client-1",
+ security_domain="domain.com",
+ return_url="http://www.google.com",
+ expiration_offset=120,
+ tags=["loan_application", "finance_dept"]
+ )
+
+ return requestBody
+
+ @classmethod
+ def _create_webform_instance(cls):
+ try:
+ accountId = cls._testConfig.account_id
+ formId = cls._published_form_id
+ requestBody = cls._get_webform_instance_create_request_body()
+
+ webFormInstance = cls._form_instance_management_api.create_instance(accountId, formId, requestBody)
+ return webFormInstance
+ except ApiException as e:
+ print("\nApiException: %s" % e)
+ assert e is None # make the test case fail in case of an API exception
+ except Exception as e:
+ print("\nException: %s" % e)
+ assert e is None # make the test case fail in case of an exception
+
+ def tearDown(self):
+ self._api_client.rest_client.pool_manager.clear()
+
+ @TestHelper.handle_exceptions
+ def test_list_instances_with_http_info_withValidParams_shouldReturnFormInstances(self):
+ account_id = self._testConfig.account_id
+ form_id = self._published_form_id
+
+ api_response = self._form_instance_management_api.list_instances_with_http_info(account_id, form_id)
+
+ self.assertIsNotNone(api_response[0], "The webFormInstances should not be null.")
+ self.assertTrue(len(api_response[0].items) > 0, "The list of instances should not be empty.")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_instance_with_http_info_withValidParams_shouldReturnFormInstance(self):
+ account_id = self._testConfig.account_id
+ form_id = self._published_form_id
+ instance_id = self._web_form_instance_id
+
+ api_response = self._form_instance_management_api.get_instance_with_http_info(account_id, form_id, instance_id)
+
+ self.assertIsNotNone(api_response[0], "The webFormInstance should not be null.")
+ self.assertEqual(form_id, api_response[0].form_id, "WebformId in request and response should match")
+ self.assertEqual(account_id, api_response[0].account_id, "AccountId in request and response should match")
+ self.assertEqual(instance_id, api_response[0].id, "InstanceId in request and response should match")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_instance_with_http_info_withInvalidAccountId_shouldReturnApiException(self):
+ account_id = self._testConfig.user_id
+ form_id = self._published_form_id
+ instance_id = self._web_form_instance_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.get_instance_with_http_info(account_id, form_id, instance_id)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_instance_with_http_info_withInvalidFormId_shouldReturnApiException(self):
+ account_id = self._testConfig.account_id
+ form_id = self._testConfig.user_id
+ instance_id = self._web_form_instance_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.get_instance_with_http_info(account_id, form_id, instance_id)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_instance_with_http_info_withInvalidInstanceId_shouldReturnApiException(self):
+ account_id = self._testConfig.account_id
+ form_id = self._published_form_id
+ instance_id = self._testConfig.user_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.get_instance_with_http_info(account_id, form_id, instance_id)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_create_instance_with_http_info_withValidParams_shouldReturnCreatedFormInstance(self):
+ accountId = self._testConfig.account_id
+ formId = self._published_form_id
+ requestBody = self._get_webform_instance_create_request_body()
+
+ apiResponse = self._form_instance_management_api.create_instance_with_http_info(accountId, formId, requestBody)
+
+ self.assertIsNotNone(apiResponse[0])
+ self.assertEqual(requestBody.client_user_id, apiResponse[0].client_user_id, "ClientUserId in request and response should match")
+ self.assertEqual(len(requestBody.tags), len(apiResponse[0].tags), "Tags length in request and response should match")
+
+ @TestHelper.handle_exceptions
+ def test_create_instance_with_http_info_withInvalidFormId_shouldReturnApiException(self):
+ accountId = self._testConfig.account_id
+ formId = self._testConfig.user_id
+ requestBody = self._get_webform_instance_create_request_body()
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.create_instance_with_http_info(accountId, formId, requestBody)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_create_instance_with_http_info_withInvalidAccountId_shouldReturnApiException(self):
+ accountId = self._testConfig.user_id
+ formId = self._published_form_id
+ requestBody = self._get_webform_instance_create_request_body()
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.create_instance_with_http_info(accountId, formId, requestBody)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_create_instance_with_http_info_withInvalidRequestObject_shouldReturnApiException(self):
+ accountId = self._testConfig.account_id
+ formId = self._published_form_id
+
+ requestBody = CreateInstanceRequestBody()
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.create_instance_with_http_info(accountId, formId, requestBody)
+ self.assertEqual(400, context.exception.status)
+
+ @TestHelper.handle_exceptions
+ def test_refresh_token_with_http_info_withValidRequestParams_shouldReturnWebFormInstanceWithNewToken(self):
+ accountId = self._testConfig.account_id
+ formId = self._published_form_id
+ existingWebFormInstance = self._web_form_instance
+ instanceId = self._web_form_instance_id
+
+ apiResponse = self._form_instance_management_api.refresh_token_with_http_info(accountId, formId, instanceId)
+
+ self.assertIsNotNone(apiResponse[0].instance_token, "InstanceToken in response should not be None")
+ self.assertNotEqual(existingWebFormInstance.instance_token, apiResponse[0].instance_token, "InstanceToken in request and response should not match")
+
+ @TestHelper.handle_exceptions
+ def test_refresh_token_with_http_info_withInvalidAccountId_shouldReturnApiException(self):
+ accountId = self._testConfig.user_id
+ formId = self._published_form_id
+ instanceId = self._web_form_instance_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.refresh_token_with_http_info(accountId, formId, instanceId)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_refresh_token_with_http_info_withInvalidFormId_shouldReturnApiException(self):
+ accountId = self._testConfig.account_id
+ formId = self._testConfig.user_id
+ instanceId = self._web_form_instance_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.refresh_token_with_http_info(accountId, formId, instanceId)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_refresh_token_with_http_info_withInvalidInstanceIdAsNull_shouldReturnApiException(self):
+ accountId = self._testConfig.account_id
+ formId = self._published_form_id
+ instanceId = self._testConfig.user_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_instance_management_api.refresh_token_with_http_info(accountId, formId, instanceId)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_form_management_api.py b/test/test_form_management_api.py
new file mode 100644
index 0000000..c8249d4
--- /dev/null
+++ b/test/test_form_management_api.py
@@ -0,0 +1,90 @@
+from __future__ import absolute_import, print_function
+
+import unittest
+
+from docusign_webforms import ApiException, FormManagementApi, FormInstanceManagementApi
+from test.test_helper import TestHelper
+
+
+class FormManagementApiTests(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls._testConfig = TestHelper()
+ cls._api_client = cls._testConfig.get_authenticated_api_client()
+
+ cls._form_management_api = FormManagementApi(cls._api_client)
+ cls._fill_dependencies()
+
+ @classmethod
+ def _fill_dependencies(cls):
+
+ try:
+ if cls._testConfig.published_webform_id is None:
+ webforms_list_data = cls._form_management_api.list_forms(cls._testConfig.account_id, is_published=True)
+
+ published_web_forms = [x for x in webforms_list_data.items if x.is_published]
+ if published_web_forms:
+ cls._published_form_id = published_web_forms[0].id
+ else:
+ cls._published_form_id = cls._testConfig.published_webform_id
+
+ except ApiException as e:
+ print("\nApiException when setting up Dependencies Info: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+ except Exception as e:
+ print("\nException when setting up Dependencies Info: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+
+ def tearDown(self):
+ self._api_client.rest_client.pool_manager.clear()
+
+ @TestHelper.handle_exceptions
+ def test_list_forms_with_http_info_withValidAccountId_shouldReturnForms(self):
+ account_id = self._testConfig.account_id
+
+ api_response = self._form_management_api.list_forms_with_http_info(account_id)
+
+ self.assertIsNotNone(api_response[0], "The list of forms should not be null.")
+ self.assertIsNotNone(api_response[0].items, "The list of forms should not be null.")
+ self.assertTrue(len(api_response[0].items) > 0, "The list of forms should not be empty.")
+
+ @TestHelper.handle_exceptions
+ def test_list_forms_with_http_info_withInvalidAccountId_shouldReturnApiException(self):
+ account_id = self._testConfig.user_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_management_api.list_forms_with_http_info(account_id)
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_with_http_info_WithValidParams_shouldReturnForm(self):
+ account_id = self._testConfig.account_id
+ form_id = self._published_form_id
+
+ api_response = self._form_management_api.get_form_with_http_info(account_id, form_id, state="active")
+
+ self.assertIsNotNone(api_response[0], "Form Object cannot be null")
+ self.assertEqual(form_id, api_response[0].id, "WebformId in request and response should match")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_with_http_info_withInvalidFormId_shouldReturnApiException(self):
+ account_id = self._testConfig.account_id
+ form_id = self._testConfig.account_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_management_api.get_form_with_http_info(account_id, form_id, state="active")
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+ @TestHelper.handle_exceptions
+ def test_get_form_with_http_info_withInvalidAccountId_shouldReturnApiException(self):
+ account_id = self._testConfig.user_id
+ form_id = self._published_form_id
+
+ with self.assertRaises(ApiException) as context:
+ self._form_management_api.get_form_with_http_info(account_id, form_id, state="active")
+ self.assertEqual(context.exception.status, 404, "Expected ApiException status code to be 404, indicating that the resource was not found.")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_helper.py b/test/test_helper.py
new file mode 100644
index 0000000..da828fc
--- /dev/null
+++ b/test/test_helper.py
@@ -0,0 +1,83 @@
+import os
+import base64
+import unittest
+import functools
+
+import docusign_webforms as docusign
+from docusign_webforms import ApiException
+
+
+class TestHelper(object):
+ def __init__(self):
+
+ self.user_name = None
+ self.user_id = None
+
+ self.client_secret = None
+ self.integrator_key = None
+ self.private_key_bytes = None
+ self.expires_in = 3600
+ self.scopes = None
+
+ self.user_info = None
+ self.account_id = None
+
+ self.published_webform_id = None
+
+ self.initialize_config()
+
+ def initialize_config(self, user_name=None, client_secret =None, user_id=None, integrator_key=None):
+ self.user_name = user_name if user_name else os.environ.get("USER_NAME")
+ self.client_secret = client_secret if client_secret else os.environ.get("CLIENT_SECRET")
+
+ self.integrator_key = integrator_key if integrator_key else os.environ.get("INTEGRATOR_KEY_JWT")
+ self.user_id = user_id if user_id else os.environ.get("USER_ID")
+
+ self.private_key_bytes = base64.b64decode(os.environ.get("PRIVATE_KEY"))
+ self.expires_in = 3600
+ self.scopes = ["signature", 'webforms_read', 'webforms_write', 'webforms_instance_read', 'webforms_instance_write']
+
+ # Note: This value is being hardcoded so that the form values can be sent accordingly in the test.
+ self.published_webform_id = 'ae0dbfc4-67c9-4dd2-863b-2823cadde398'
+
+ def get_api_client(self):
+ api_client = docusign.ApiClient()
+ docusign.configuration.api_client = api_client
+ return api_client
+
+ def get_authenticated_api_client(self):
+ try:
+ api_client = self.get_api_client()
+ token = (api_client.request_jwt_user_token(client_id=self.integrator_key,
+ user_id=self.user_id,
+ oauth_host_name=api_client.oauth_host_name,
+ private_key_bytes=self.private_key_bytes,
+ expires_in=3600,
+ scopes=self.scopes))
+
+ self.user_info = api_client.get_user_info(token.access_token)
+ if self.user_info.accounts and len(self.user_info.accounts) > 0:
+ self.account_id = self.user_info.accounts[0].account_id
+
+ except ApiException as e:
+ print("\nApiException when setting up DocuSign Api Client: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+ except Exception as e:
+ print("\nException when calling DocuSign Api Client: %s" % e)
+ raise Exception("An unexpected error occurred. Test case should not fail here.")
+
+ return api_client
+
+ @staticmethod
+ def handle_exceptions(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except ApiException as e:
+ print("An ApiException occurred:", e)
+ unittest.TestCase().fail("An unexpected error occurred. Test case should not fail here.")
+ except Exception as e:
+ print("An Exception occurred:", e)
+ unittest.TestCase().fail("An unexpected error occurred. Test case should not fail here.")
+ return wrapper