Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Release History
Upcoming
++++++++

1.4.1 (2016-02-11)
++++++++++++++++++

- Files now support getting a direct download url.

1.4.0 (2016-01-05)
++++++++++++++++++

Expand Down
51 changes: 51 additions & 0 deletions boxsdk/object/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,54 @@ def metadata(self, scope='global', template='properties'):
:class:`Metadata`
"""
return Metadata(self._session, self, scope, template)

def get_shared_link_download_url(
self,
access=None,
etag=None,
unshared_at=None,
allow_preview=None,
password=None,
):
"""
Get a shared link download url for the file with the given access permissions.
This url is a direct download url for the file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a sentence or a link to explain the difference between shared link and direct url? I guess it might be confusing to a few users.

:param access:
Determines who can access the shared link. May be open, company, or collaborators. If no access is
specified, the default access will be used.
:type access:
`unicode` or None
:param etag:
If specified, instruct the Box API to create the link only if the current version's etag matches.
:type etag:
`unicode` or None
:param unshared_at:
The date on which this link should be disabled. May only be set if the current user is not a free user
and has permission to set expiration dates.
:type unshared_at:
:class:`datetime.date` or None
:param allow_preview:
Whether or not the item being shared can be previewed when accessed via the shared link.
If this parameter is None, the default setting will be used.
:type allow_preview:
`bool` or None
:param password:
The password required to view this link. If no password is specified then no password will be set.
Please notice that this is a premium feature, which might not be available to your app.
:type password:
`unicode` or None
:returns:
The URL of the shared link that allows direct download.
:rtype:
`unicode`
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
"""
item = self.create_shared_link(
access=access,
etag=etag,
unshared_at=unshared_at,
allow_preview=allow_preview,
password=password,
)
return item.shared_link['download_url']
79 changes: 73 additions & 6 deletions boxsdk/object/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,17 @@ def move(self, parent_folder):
}
return self.update_info(data)

def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_download=None, allow_preview=None, password=None):
"""Get a shared link for the item with the given access permissions.
def create_shared_link(
self,
access=None,
etag=None,
unshared_at=None,
allow_download=None,
allow_preview=None,
password=None,
):
"""
Create a shared link for the item with the given access permissions.

:param access:
Determines who can access the shared link. May be open, company, or collaborators. If no access is
Expand Down Expand Up @@ -191,10 +200,11 @@ def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_downlo
Please notice that this is a premium feature, which might not be available to your app.
:type password:
`unicode` or None
:returns:
The URL of the shared link.
:return:
The updated object with s shared link.
Returns a new object of the same type, without modifying the original object passed as self.
:rtype:
`unicode`
:class:`Item`
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
"""
data = {
Expand All @@ -216,7 +226,64 @@ def get_shared_link(self, access=None, etag=None, unshared_at=None, allow_downlo
if password is not None:
data['shared_link']['password'] = password

item = self.update_info(data, etag=etag)
return self.update_info(data, etag=etag)

def get_shared_link(
self,
access=None,
etag=None,
unshared_at=None,
allow_download=None,
allow_preview=None,
password=None,
):
"""
Get a shared link for the item with the given access permissions.
This url leads to a Box.com shared link page, where the item can be previewed, downloaded, etc.

:param access:
Determines who can access the shared link. May be open, company, or collaborators. If no access is
specified, the default access will be used.
:type access:
`unicode` or None
:param etag:
If specified, instruct the Box API to create the link only if the current version's etag matches.
:type etag:
`unicode` or None
:param unshared_at:
The date on which this link should be disabled. May only be set if the current user is not a free user
and has permission to set expiration dates.
:type unshared_at:
:class:`datetime.date` or None
:param allow_download:
Whether or not the item being shared can be downloaded when accessed via the shared link.
If this parameter is None, the default setting will be used.
:type allow_download:
`bool` or None
:param allow_preview:
Whether or not the item being shared can be previewed when accessed via the shared link.
If this parameter is None, the default setting will be used.
:type allow_preview:
`bool` or None
:param password:
The password required to view this link. If no password is specified then no password will be set.
Please notice that this is a premium feature, which might not be available to your app.
:type password:
`unicode` or None
:returns:
The URL of the shared link.
:rtype:
`unicode`
:raises: :class:`BoxAPIException` if the specified etag doesn't match the latest version of the item.
"""
item = self.create_shared_link(
access=access,
etag=etag,
unshared_at=unshared_at,
allow_download=allow_download,
allow_preview=allow_preview,
password=password,
)
return item.shared_link['url']

def remove_shared_link(self, etag=None):
Expand Down
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[bdist_wheel]
# This flag says that the code is written to work on both Python 2 and Python
# 3. If at all possible, it is good practice to do this. If you cannot, you
# will need to generate wheels for each Python version that you support.
universal=1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def main():
install_requires.append('ordereddict>=1.1')
setup(
name='boxsdk',
version='1.4.0',
version='1.4.1',
description='Official Box Python SDK',
long_description=open(join(base_dir, 'README.rst')).read(),
author='Box',
Expand Down
26 changes: 26 additions & 0 deletions test/unit/object/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# coding: utf-8

from __future__ import unicode_literals
from datetime import date
import os
from mock import Mock
import pytest
Expand Down Expand Up @@ -162,3 +163,28 @@ def file_size(request):
def mock_group(mock_box_session, mock_group_id):
group = Group(mock_box_session, mock_group_id)
return group


@pytest.fixture(params=(True, False, None))
def shared_link_can_download(request):
return request.param


@pytest.fixture(params=(True, False, None))
def shared_link_can_preview(request):
return request.param


@pytest.fixture(params=('open', None))
def shared_link_access(request):
return request.param


@pytest.fixture(params=('hunter2', None))
def shared_link_password(request):
return request.param


@pytest.fixture(params=(date(2015, 5, 5), None))
def shared_link_unshared_at(request):
return request.param
40 changes: 40 additions & 0 deletions test/unit/object/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,43 @@ def test_preflight_check(
expect_json_response=False,
data=expected_data,
)


def test_get_shared_link_download_url(
test_file,
mock_box_session,
shared_link_access,
shared_link_unshared_at,
shared_link_password,
shared_link_can_preview,
test_url,
etag,
if_match_header,
):
# pylint:disable=redefined-outer-name, protected-access
expected_url = test_file.get_url()
mock_box_session.put.return_value.json.return_value = {'shared_link': {'url': None, 'download_url': test_url}}
expected_data = {'shared_link': {}}
if shared_link_access is not None:
expected_data['shared_link']['access'] = shared_link_access
if shared_link_unshared_at is not None:
expected_data['shared_link']['unshared_at'] = shared_link_unshared_at.isoformat()
if shared_link_can_preview is not None:
expected_data['shared_link']['permissions'] = permissions = {}
permissions['can_preview'] = shared_link_can_preview
if shared_link_password is not None:
expected_data['shared_link']['password'] = shared_link_password
url = test_file.get_shared_link_download_url(
etag=etag,
access=shared_link_access,
unshared_at=shared_link_unshared_at,
password=shared_link_password,
allow_preview=shared_link_can_preview,
)
mock_box_session.put.assert_called_once_with(
expected_url,
data=json.dumps(expected_data),
headers=if_match_header,
params=None,
)
assert url == test_url
26 changes: 0 additions & 26 deletions test/unit/object/test_item.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# coding: utf-8

from __future__ import unicode_literals
from datetime import date
import json
import pytest

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


@pytest.fixture(params=(True, False, None))
def shared_link_can_download(request):
return request.param


@pytest.fixture(params=(True, False, None))
def shared_link_can_preview(request):
return request.param


@pytest.fixture(params=('open', None))
def shared_link_access(request):
return request.param


@pytest.fixture(params=('hunter2', None))
def shared_link_password(request):
return request.param


@pytest.fixture(params=(date(2015, 5, 5), None))
def shared_link_unshared_at(request):
return request.param


def test_get_shared_link(
test_item_and_response,
mock_box_session,
Expand Down