Skip to content

Commit fbc783d

Browse files
feat: adds get sign template and get sign templates methods on Client (#835)
--------- Co-authored-by: Minh Nguyen Cong <mcong@box.com>
1 parent f210f00 commit fbc783d

File tree

9 files changed

+409
-1
lines changed

9 files changed

+409
-1
lines changed

boxsdk/client/client.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from boxsdk.object.group_membership import GroupMembership
5959
from boxsdk.object.enterprise import Enterprise
6060
from boxsdk.object.collection import Collection
61+
from boxsdk.object.sign_template import SignTemplate
6162
from boxsdk.pagination.box_object_collection import BoxObjectCollection
6263

6364

@@ -1635,3 +1636,57 @@ def get_sign_requests(
16351636
fields=fields,
16361637
return_full_pages=False,
16371638
)
1639+
1640+
def sign_template(self, sign_template_id: str) -> 'SignTemplate':
1641+
"""
1642+
Initialize a :class:`SignTemplate` object, whose box id is sign_template_id.
1643+
1644+
:param sign_template_id:
1645+
The box id of the :class:`SignTemplate` object.
1646+
:return:
1647+
A :class:`SignTemplate` object with the given sign_template_id.
1648+
"""
1649+
return self.translator.get('sign_template')(session=self._session, object_id=sign_template_id)
1650+
1651+
@api_call
1652+
def get_sign_templates(
1653+
self,
1654+
limit: Optional[int] = None,
1655+
marker: Optional[str] = None,
1656+
) -> 'BoxObjectCollection':
1657+
"""
1658+
Returns all sign templates
1659+
1660+
:param limit:
1661+
The maximum number of entries to return per page. If not specified, then will use the server-side default.
1662+
:param marker:
1663+
The paging marker to start paging from.
1664+
:returns:
1665+
Sign templates
1666+
"""
1667+
return MarkerBasedObjectCollection(
1668+
session=self._session,
1669+
url=self.get_url("sign_templates"),
1670+
limit=limit,
1671+
marker=marker,
1672+
return_full_pages=False,
1673+
)
1674+
1675+
@api_call
1676+
def get_sign_template(
1677+
self,
1678+
sign_template_id: str,
1679+
) -> Any:
1680+
"""
1681+
Returns a sign template
1682+
1683+
:param sign_template_id:
1684+
ID of Sign template to fetch
1685+
:returns:
1686+
Sign template
1687+
"""
1688+
response = self._session.get(f"{self._session.get_url('sign_templates')}/{sign_template_id}")
1689+
return self.translator.translate(
1690+
session=self._session,
1691+
response_object=response.json(),
1692+
)

boxsdk/object/sign_template.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from typing import Any
2+
3+
from .base_object import BaseObject
4+
5+
6+
class SignTemplate(BaseObject):
7+
"""
8+
Represents a Sign Template used by Box Sign
9+
"""
10+
_item_type = 'sign-template'
11+
12+
def get_url(self, *args: Any) -> str:
13+
"""
14+
Returns the url for this sign template.
15+
"""
16+
return self._session.get_url('sign_templates', self._object_id, *args)

docs/source/boxsdk.object.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ boxsdk.object.file module
148148
:undoc-members:
149149
:show-inheritance:
150150

151+
boxsdk.object.file\_request module
152+
----------------------------------
153+
154+
.. automodule:: boxsdk.object.file_request
155+
:members:
156+
:undoc-members:
157+
:show-inheritance:
158+
151159
boxsdk.object.file\_version module
152160
----------------------------------
153161

@@ -300,6 +308,14 @@ boxsdk.object.sign\_request module
300308
:undoc-members:
301309
:show-inheritance:
302310

311+
boxsdk.object.sign\_template module
312+
-----------------------------------
313+
314+
.. automodule:: boxsdk.object.sign_template
315+
:members:
316+
:undoc-members:
317+
:show-inheritance:
318+
303319
boxsdk.object.storage\_policy module
304320
------------------------------------
305321

docs/usage/sign_requests.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Get All Sign Requests
5050
------------------------
5151

5252
Calling the [`client.get_sign_requests()`][get-all-sign-requests]
53-
will return an iterable that will page through all the Sign Requests. This method offers `limit` and `fields` parameters. The `limit` parameter specifies the maximum number of items to be returned in a single response. The `fields` parameter is used to specify what additional properties should be returned on the return object. For more information on what `fields` are available, please refer to the [developer documentation](https://developer.box.com/guides/sign-request/).
53+
will return an iterable that will page through all the Sign Requests. This method offers `limit` and `fields` parameters. The `limit` parameter specifies the maximum number of items to be returned in a single response. The `fields` parameter is used to specify what additional properties should be returned on the return object. For more information on what `fields` are available, please refer to the [developer documentation](https://developer.box.com/guides/box-sign/).
5454

5555
<!-- sample get_sign_requests -->
5656
```python

docs/usage/sign_templates.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Sign Templates
2+
==============
3+
4+
Sign Templates are reusable templates that can be used to create Sign Requests. For now, Sign Templates can only be created through the Box web application.
5+
6+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
7+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
8+
9+
- [Get All Sign Templates](#get-all-sign-templates)
10+
- [Get Sign Template by ID](#get-sign-template-by-id)
11+
12+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
13+
14+
Get All Sign Templates
15+
----------------------
16+
17+
Calling the [`client.get_sign_templates()`][get-all-sign-templates] method will return an iterable that will page through all the Sign Templates. This method offers `limit` parameter. The `limit` parameter specifies the maximum number of items to be returned in a single response.
18+
19+
<!-- sample get_sign_templates -->
20+
```python
21+
sign_templates = client.get_sign_templates()
22+
for sign_template in sign_templates:
23+
print(f'(Sign Template ID: {sign_template.id})')
24+
```
25+
26+
[get-all-sign-templates]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.client.html#boxsdk.client.client.Client.get_sign_templates
27+
28+
Get Sign Template by ID
29+
-----------------------
30+
31+
Calling the [`client.get_sign_template(template_id)`][get-sign-template] method will return a Sign Template object.
32+
33+
<!-- sample get_sign_template -->
34+
```python
35+
sign_template = client.get_sign_template('12345')
36+
print(f'(Sign Template ID: {sign_template.id})')
37+
```
38+
39+
[get-sign-template]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.client.html#boxsdk.client.client.Client.get_sign_template
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from boxsdk.pagination.box_object_collection import BoxObjectCollection
2+
3+
from test.integration_new import CLIENT
4+
5+
6+
def test_get_sign_templates():
7+
sign_templates = CLIENT.get_sign_templates()
8+
assert isinstance(sign_templates, BoxObjectCollection)

test/unit/client/test_client.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from boxsdk.object.legal_hold_policy_assignment import LegalHoldPolicyAssignment
4242
from boxsdk.object.metadata_cascade_policy import MetadataCascadePolicy
4343
from boxsdk.object.sign_request import SignRequest
44+
from boxsdk.object.sign_template import SignTemplate
4445
from boxsdk.object.task import Task
4546
from boxsdk.object.task_assignment import TaskAssignment
4647
from boxsdk.object.webhook import Webhook
@@ -1664,6 +1665,105 @@ def mock_sign_request_response():
16641665
return mock_sign_request
16651666

16661667

1668+
@pytest.fixture(scope='module')
1669+
def mock_sign_template_response():
1670+
mock_sign_template = {
1671+
"id": "93153068-5420-467b-b8ef-8e54bfb7be42",
1672+
"type": "sign-template",
1673+
"name": "important-file.pdf",
1674+
"email_message": "Please sign this document.\n\nKind regards",
1675+
"email_subject": "Box User (boxuser@box.com) has requested your signature on a document",
1676+
"parent_folder": {
1677+
"id": "123456789",
1678+
"etag": "0",
1679+
"type": "folder",
1680+
"sequence_id": "0",
1681+
"name": "My Sign Requests"
1682+
},
1683+
"auto_expire_days": "null",
1684+
"source_files": [
1685+
{
1686+
"id": "123456",
1687+
"etag": "0",
1688+
"type": "file",
1689+
"sequence_id": "0",
1690+
"sha1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1691+
"file_version": {
1692+
"id": "123456",
1693+
"type": "file_version",
1694+
"sha1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
1695+
}
1696+
}
1697+
],
1698+
"are_email_settings_locked": "false",
1699+
"are_fields_locked": "false",
1700+
"are_files_locked": "false",
1701+
"are_options_locked": "false",
1702+
"are_recipients_locked": "false",
1703+
"signers": [
1704+
{
1705+
"email": "",
1706+
"label": "",
1707+
"public_id": "AAQXQXJZ4",
1708+
"role": "final_copy_reader",
1709+
"is_in_person": "false",
1710+
"order": 1,
1711+
"inputs": []
1712+
},
1713+
{
1714+
"email": "",
1715+
"label": "",
1716+
"public_id": "13XQXJZ4",
1717+
"role": "signer",
1718+
"is_in_person": "false",
1719+
"order": 1,
1720+
"inputs": [
1721+
{
1722+
"document_tag_id": None,
1723+
"id": "0260f921-3b52-477f-ae74-0b0b0b0b0b0b",
1724+
"type": "signature",
1725+
"text_value": None,
1726+
"is_required": True,
1727+
"coordinates": {
1728+
"x": 0.27038464059712,
1729+
"y": 0.10051756244533624
1730+
},
1731+
"dimensions": {
1732+
"width": 0.23570031566618235,
1733+
"height": 0.04781003891921971
1734+
},
1735+
"date_value": None,
1736+
"page_index": 0,
1737+
"checkbox_value": None,
1738+
"document_id": "2fdf9003-d798-40ee-be7f-0b0b0b0b0b0b",
1739+
"content_type": "signature",
1740+
"dropdown_choices": None,
1741+
"group_id": None,
1742+
"label": None
1743+
}
1744+
]
1745+
}
1746+
],
1747+
"ready_sign_link": None,
1748+
"custom_branding": None,
1749+
"days_valid": 0,
1750+
"additional_info": {
1751+
"non_editable": [],
1752+
"required": {
1753+
"signers": [
1754+
[
1755+
"email"
1756+
],
1757+
[
1758+
"email"
1759+
]
1760+
]
1761+
}
1762+
}
1763+
}
1764+
return mock_sign_template
1765+
1766+
16671767
def test_get_sign_requests(mock_client, mock_box_session, mock_sign_request_response):
16681768
expected_url = f'{API.BASE_API_URL}/sign_requests'
16691769

@@ -1754,3 +1854,53 @@ def test_file_request(mock_client):
17541854

17551855
assert isinstance(file_request, FileRequest)
17561856
assert file_request.object_id == file_request_id
1857+
1858+
1859+
def test_get_sign_templates_from_id(mock_client, mock_box_session, mock_sign_template_response):
1860+
test_sign_template_id = '93153068-5420-467b-b8ef-8e54bfb7be42'
1861+
expected_url = f'{API.BASE_API_URL}/sign_templates/{test_sign_template_id}'
1862+
mock_box_session.get.return_value.json.return_value = mock_sign_template_response
1863+
1864+
sign_template = mock_client.sign_template(test_sign_template_id).get()
1865+
1866+
mock_box_session.get.assert_called_once_with(expected_url, headers=None, params=None)
1867+
1868+
assert isinstance(sign_template, SignTemplate)
1869+
assert sign_template.id == '93153068-5420-467b-b8ef-8e54bfb7be42'
1870+
1871+
1872+
def test_get_sign_template(mock_client, mock_box_session, mock_sign_template_response):
1873+
test_sign_template_id = '93153068-5420-467b-b8ef-8e54bfb7be42'
1874+
expected_url = f'{API.BASE_API_URL}/sign_templates/{test_sign_template_id}'
1875+
mock_box_session.get.return_value.json.return_value = mock_sign_template_response
1876+
1877+
sign_template = mock_client.get_sign_template(test_sign_template_id)
1878+
1879+
mock_box_session.get.assert_called_once_with(expected_url)
1880+
1881+
assert isinstance(sign_template, SignTemplate)
1882+
assert sign_template.id == '93153068-5420-467b-b8ef-8e54bfb7be42'
1883+
assert sign_template.name == 'important-file.pdf'
1884+
assert sign_template.email_message == 'Please sign this document.\n\nKind regards'
1885+
1886+
1887+
def test_get_sign_templates(mock_client, mock_box_session, mock_sign_template_response):
1888+
expected_url = f'{API.BASE_API_URL}/sign_templates'
1889+
1890+
mock_sign_template = mock_sign_template_response
1891+
mock_box_session.get.return_value.json.return_value = {
1892+
'total_count': 1,
1893+
'limit': 100,
1894+
'entries': [mock_sign_template],
1895+
'next_marker': None,
1896+
'previous_marker': None,
1897+
}
1898+
1899+
sign_templates = mock_client.get_sign_templates()
1900+
1901+
sign_template = sign_templates.next()
1902+
1903+
mock_box_session.get.assert_called_once_with(expected_url, params={})
1904+
assert isinstance(sign_template, SignTemplate)
1905+
assert sign_template.id == '93153068-5420-467b-b8ef-8e54bfb7be42'
1906+
assert sign_template.name == 'important-file.pdf'

test/unit/object/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment
2626
from boxsdk.object.search import Search
2727
from boxsdk.object.sign_request import SignRequest
28+
from boxsdk.object.sign_template import SignTemplate
2829
from boxsdk.object.storage_policy import StoragePolicy
2930
from boxsdk.object.storage_policy_assignment import StoragePolicyAssignment
3031
from boxsdk.object.terms_of_service import TermsOfService
@@ -420,3 +421,8 @@ def test_sign_request(mock_box_session, mock_object_id):
420421
@pytest.fixture()
421422
def test_file_request(mock_box_session, mock_object_id):
422423
return FileRequest(mock_box_session, mock_object_id)
424+
425+
426+
@pytest.fixture()
427+
def test_sign_template(mock_box_session, mock_object_id):
428+
return SignTemplate(mock_box_session, mock_object_id)

0 commit comments

Comments
 (0)