Skip to content

Commit fb4f243

Browse files
committed
Merge pull request #114 from Jeff-Meadows/slinkurl
Expose file.get_shared_link_download_url method.
2 parents 8b6afa5 + d046240 commit fb4f243

File tree

8 files changed

+201
-33
lines changed

8 files changed

+201
-33
lines changed

HISTORY.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ Release History
66
Upcoming
77
++++++++
88

9+
1.4.1 (2016-02-11)
10+
++++++++++++++++++
11+
12+
- Files now support getting a direct download url.
13+
914
1.4.0 (2016-01-05)
1015
++++++++++++++++++
1116

boxsdk/object/file.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,54 @@ def metadata(self, scope='global', template='properties'):
237237
:class:`Metadata`
238238
"""
239239
return Metadata(self._session, self, scope, template)
240+
241+
def get_shared_link_download_url(
242+
self,
243+
access=None,
244+
etag=None,
245+
unshared_at=None,
246+
allow_preview=None,
247+
password=None,
248+
):
249+
"""
250+
Get a shared link download url for the file with the given access permissions.
251+
This url is a direct download url for the file.
252+
253+
:param access:
254+
Determines who can access the shared link. May be open, company, or collaborators. If no access is
255+
specified, the default access will be used.
256+
:type access:
257+
`unicode` or None
258+
:param etag:
259+
If specified, instruct the Box API to create the link only if the current version's etag matches.
260+
:type etag:
261+
`unicode` or None
262+
:param unshared_at:
263+
The date on which this link should be disabled. May only be set if the current user is not a free user
264+
and has permission to set expiration dates.
265+
:type unshared_at:
266+
:class:`datetime.date` or None
267+
:param allow_preview:
268+
Whether or not the item being shared can be previewed when accessed via the shared link.
269+
If this parameter is None, the default setting will be used.
270+
:type allow_preview:
271+
`bool` or None
272+
:param password:
273+
The password required to view this link. If no password is specified then no password will be set.
274+
Please notice that this is a premium feature, which might not be available to your app.
275+
:type password:
276+
`unicode` or None
277+
:returns:
278+
The URL of the shared link that allows direct download.
279+
:rtype:
280+
`unicode`
281+
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
282+
"""
283+
item = self.create_shared_link(
284+
access=access,
285+
etag=etag,
286+
unshared_at=unshared_at,
287+
allow_preview=allow_preview,
288+
password=password,
289+
)
290+
return item.shared_link['download_url']

boxsdk/object/item.py

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,17 @@ def move(self, parent_folder):
159159
}
160160
return self.update_info(data)
161161

162-
def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_download=None, allow_preview=None, password=None):
163-
"""Get a shared link for the item with the given access permissions.
162+
def create_shared_link(
163+
self,
164+
access=None,
165+
etag=None,
166+
unshared_at=None,
167+
allow_download=None,
168+
allow_preview=None,
169+
password=None,
170+
):
171+
"""
172+
Create a shared link for the item with the given access permissions.
164173
165174
:param access:
166175
Determines who can access the shared link. May be open, company, or collaborators. If no access is
@@ -191,10 +200,11 @@ def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_downlo
191200
Please notice that this is a premium feature, which might not be available to your app.
192201
:type password:
193202
`unicode` or None
194-
:returns:
195-
The URL of the shared link.
203+
:return:
204+
The updated object with s shared link.
205+
Returns a new object of the same type, without modifying the original object passed as self.
196206
:rtype:
197-
`unicode`
207+
:class:`Item`
198208
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
199209
"""
200210
data = {
@@ -216,7 +226,64 @@ def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_downlo
216226
if password is not None:
217227
data['shared_link']['password'] = password
218228

219-
item = self.update_info(data, etag=etag)
229+
return self.update_info(data, etag=etag)
230+
231+
def get_shared_link(
232+
self,
233+
access=None,
234+
etag=None,
235+
unshared_at=None,
236+
allow_download=None,
237+
allow_preview=None,
238+
password=None,
239+
):
240+
"""
241+
Get a shared link for the item with the given access permissions.
242+
This url leads to a Box.com shared link page, where the item can be previewed, downloaded, etc.
243+
244+
:param access:
245+
Determines who can access the shared link. May be open, company, or collaborators. If no access is
246+
specified, the default access will be used.
247+
:type access:
248+
`unicode` or None
249+
:param etag:
250+
If specified, instruct the Box API to create the link only if the current version's etag matches.
251+
:type etag:
252+
`unicode` or None
253+
:param unshared_at:
254+
The date on which this link should be disabled. May only be set if the current user is not a free user
255+
and has permission to set expiration dates.
256+
:type unshared_at:
257+
:class:`datetime.date` or None
258+
:param allow_download:
259+
Whether or not the item being shared can be downloaded when accessed via the shared link.
260+
If this parameter is None, the default setting will be used.
261+
:type allow_download:
262+
`bool` or None
263+
:param allow_preview:
264+
Whether or not the item being shared can be previewed when accessed via the shared link.
265+
If this parameter is None, the default setting will be used.
266+
:type allow_preview:
267+
`bool` or None
268+
:param password:
269+
The password required to view this link. If no password is specified then no password will be set.
270+
Please notice that this is a premium feature, which might not be available to your app.
271+
:type password:
272+
`unicode` or None
273+
:returns:
274+
The URL of the shared link.
275+
:rtype:
276+
`unicode`
277+
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
278+
"""
279+
item = self.create_shared_link(
280+
access=access,
281+
etag=etag,
282+
unshared_at=unshared_at,
283+
allow_download=allow_download,
284+
allow_preview=allow_preview,
285+
password=password,
286+
)
220287
return item.shared_link['url']
221288

222289
def remove_shared_link(self, etag=None):

setup.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[bdist_wheel]
2+
# This flag says that the code is written to work on both Python 2 and Python
3+
# 3. If at all possible, it is good practice to do this. If you cannot, you
4+
# will need to generate wheels for each Python version that you support.
5+
universal=1

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def main():
6161
install_requires.append('ordereddict>=1.1')
6262
setup(
6363
name='boxsdk',
64-
version='1.4.0',
64+
version='1.4.1',
6565
description='Official Box Python SDK',
6666
long_description=open(join(base_dir, 'README.rst')).read(),
6767
author='Box',

test/unit/object/conftest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding: utf-8
22

33
from __future__ import unicode_literals
4+
from datetime import date
45
import os
56
from mock import Mock
67
import pytest
@@ -162,3 +163,28 @@ def file_size(request):
162163
def mock_group(mock_box_session, mock_group_id):
163164
group = Group(mock_box_session, mock_group_id)
164165
return group
166+
167+
168+
@pytest.fixture(params=(True, False, None))
169+
def shared_link_can_download(request):
170+
return request.param
171+
172+
173+
@pytest.fixture(params=(True, False, None))
174+
def shared_link_can_preview(request):
175+
return request.param
176+
177+
178+
@pytest.fixture(params=('open', None))
179+
def shared_link_access(request):
180+
return request.param
181+
182+
183+
@pytest.fixture(params=('hunter2', None))
184+
def shared_link_password(request):
185+
return request.param
186+
187+
188+
@pytest.fixture(params=(date(2015, 5, 5), None))
189+
def shared_link_unshared_at(request):
190+
return request.param

test/unit/object/test_file.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,43 @@ def test_preflight_check(
234234
expect_json_response=False,
235235
data=expected_data,
236236
)
237+
238+
239+
def test_get_shared_link_download_url(
240+
test_file,
241+
mock_box_session,
242+
shared_link_access,
243+
shared_link_unshared_at,
244+
shared_link_password,
245+
shared_link_can_preview,
246+
test_url,
247+
etag,
248+
if_match_header,
249+
):
250+
# pylint:disable=redefined-outer-name, protected-access
251+
expected_url = test_file.get_url()
252+
mock_box_session.put.return_value.json.return_value = {'shared_link': {'url': None, 'download_url': test_url}}
253+
expected_data = {'shared_link': {}}
254+
if shared_link_access is not None:
255+
expected_data['shared_link']['access'] = shared_link_access
256+
if shared_link_unshared_at is not None:
257+
expected_data['shared_link']['unshared_at'] = shared_link_unshared_at.isoformat()
258+
if shared_link_can_preview is not None:
259+
expected_data['shared_link']['permissions'] = permissions = {}
260+
permissions['can_preview'] = shared_link_can_preview
261+
if shared_link_password is not None:
262+
expected_data['shared_link']['password'] = shared_link_password
263+
url = test_file.get_shared_link_download_url(
264+
etag=etag,
265+
access=shared_link_access,
266+
unshared_at=shared_link_unshared_at,
267+
password=shared_link_password,
268+
allow_preview=shared_link_can_preview,
269+
)
270+
mock_box_session.put.assert_called_once_with(
271+
expected_url,
272+
data=json.dumps(expected_data),
273+
headers=if_match_header,
274+
params=None,
275+
)
276+
assert url == test_url

test/unit/object/test_item.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# coding: utf-8
22

33
from __future__ import unicode_literals
4-
from datetime import date
54
import json
65
import pytest
76

@@ -56,31 +55,6 @@ def test_move_item(test_item_and_response, mock_box_session, test_folder, mock_o
5655
assert isinstance(move_response, test_item.__class__)
5756

5857

59-
@pytest.fixture(params=(True, False, None))
60-
def shared_link_can_download(request):
61-
return request.param
62-
63-
64-
@pytest.fixture(params=(True, False, None))
65-
def shared_link_can_preview(request):
66-
return request.param
67-
68-
69-
@pytest.fixture(params=('open', None))
70-
def shared_link_access(request):
71-
return request.param
72-
73-
74-
@pytest.fixture(params=('hunter2', None))
75-
def shared_link_password(request):
76-
return request.param
77-
78-
79-
@pytest.fixture(params=(date(2015, 5, 5), None))
80-
def shared_link_unshared_at(request):
81-
return request.param
82-
83-
8458
def test_get_shared_link(
8559
test_item_and_response,
8660
mock_box_session,

0 commit comments

Comments
 (0)