Skip to content

Commit

Permalink
feat: Support getting file download URL and file thumbnail URL (box/b…
Browse files Browse the repository at this point in the history
  • Loading branch information
box-sdk-build authored Dec 2, 2024
1 parent bd7b9f6 commit fd609ab
Show file tree
Hide file tree
Showing 12 changed files with 363 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .codegen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "engineHash": "5a3b4bc", "specHash": "544d370", "version": "1.7.0" }
{ "engineHash": "f073ce3", "specHash": "544d370", "version": "1.7.0" }
1 change: 1 addition & 0 deletions box_sdk_gen/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ def make_request(self, fetch_options: FetchOptions) -> FetchResponse:
multipart_data=fetch_options.multipart_data,
content_type=fetch_options.content_type,
response_format=fetch_options.response_format,
follow_redirects=fetch_options.follow_redirects,
)
return fetch(enriched_fetch_options)

Expand Down
76 changes: 76 additions & 0 deletions box_sdk_gen/managers/downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,82 @@ def __init__(
self.auth = auth
self.network_session = network_session

def get_download_file_url(
self,
file_id: str,
*,
version: Optional[str] = None,
access_token: Optional[str] = None,
range: Optional[str] = None,
boxapi: Optional[str] = None,
extra_headers: Optional[Dict[str, Optional[str]]] = None
) -> str:
"""
Returns the contents of a file in binary format.
:param file_id: The unique identifier that represents a file.
The ID for any file can be determined
by visiting a file in the web application
and copying the ID from the URL. For example,
for the URL `https://*.app.box.com/files/123`
the `file_id` is `123`.
Example: "12345"
:type file_id: str
:param version: The file version to download, defaults to None
:type version: Optional[str], optional
:param access_token: An optional access token that can be used to pre-authenticate this request, which means that a download link can be shared with a browser or a third party service without them needing to know how to handle the authentication.
When using this parameter, please make sure that the access token is sufficiently scoped down to only allow read access to that file and no other files or folders., defaults to None
:type access_token: Optional[str], optional
:param range: The byte range of the content to download.
The format `bytes={start_byte}-{end_byte}` can be used to specify
what section of the file to download., defaults to None
:type range: Optional[str], optional
:param boxapi: The URL, and optional password, for the shared link of this item.
This header can be used to access items that have not been
explicitly shared with a user.
Use the format `shared_link=[link]` or if a password is required then
use `shared_link=[link]&shared_link_password=[password]`.
This header can be used on the file or folder shared, as well as on any files
or folders nested within the item., defaults to None
:type boxapi: Optional[str], optional
:param extra_headers: Extra headers that will be included in the HTTP request., defaults to None
:type extra_headers: Optional[Dict[str, Optional[str]]], optional
"""
if extra_headers is None:
extra_headers = {}
query_params_map: Dict[str, str] = prepare_params(
{'version': to_string(version), 'access_token': to_string(access_token)}
)
headers_map: Dict[str, str] = prepare_params(
{'range': to_string(range), 'boxapi': to_string(boxapi), **extra_headers}
)
response: FetchResponse = fetch(
FetchOptions(
url=''.join(
[
self.network_session.base_urls.base_url,
'/2.0/files/',
to_string(file_id),
'/content',
]
),
method='GET',
params=query_params_map,
headers=headers_map,
response_format=ResponseFormat.NO_CONTENT,
auth=self.auth,
network_session=self.network_session,
follow_redirects=False,
)
)
if response.headers['location'] == None:
raise BoxSDKError(message='No location header in response')
return response.headers['location']

def download_file(
self,
file_id: str,
Expand Down
94 changes: 94 additions & 0 deletions box_sdk_gen/managers/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ def __init__(self, id: str, **kwargs):
self.id = id


class GetFileThumbnailUrlExtension(str, Enum):
PNG = 'png'
JPG = 'jpg'


class GetFileThumbnailByIdExtension(str, Enum):
PNG = 'png'
JPG = 'jpg'
Expand Down Expand Up @@ -595,6 +600,95 @@ def copy_file(
)
return deserialize(response.data, FileFull)

def get_file_thumbnail_url(
self,
file_id: str,
extension: GetFileThumbnailUrlExtension,
*,
min_height: Optional[int] = None,
min_width: Optional[int] = None,
max_height: Optional[int] = None,
max_width: Optional[int] = None,
extra_headers: Optional[Dict[str, Optional[str]]] = None
) -> str:
"""
Retrieves a thumbnail, or smaller image representation, of a file.
Sizes of `32x32`,`64x64`, `128x128`, and `256x256` can be returned in
the `.png` format and sizes of `32x32`, `160x160`, and `320x320`
can be returned in the `.jpg` format.
Thumbnails can be generated for the image and video file formats listed
[found on our community site][1].
[1]: https://community.box.com/t5/Migrating-and-Previewing-Content/File-Types-and-Fonts-Supported-in-Box-Content-Preview/ta-p/327
:param file_id: The unique identifier that represents a file.
The ID for any file can be determined
by visiting a file in the web application
and copying the ID from the URL. For example,
for the URL `https://*.app.box.com/files/123`
the `file_id` is `123`.
Example: "12345"
:type file_id: str
:param extension: The file format for the thumbnail
Example: "png"
:type extension: GetFileThumbnailUrlExtension
:param min_height: The minimum height of the thumbnail, defaults to None
:type min_height: Optional[int], optional
:param min_width: The minimum width of the thumbnail, defaults to None
:type min_width: Optional[int], optional
:param max_height: The maximum height of the thumbnail, defaults to None
:type max_height: Optional[int], optional
:param max_width: The maximum width of the thumbnail, defaults to None
:type max_width: Optional[int], optional
:param extra_headers: Extra headers that will be included in the HTTP request., defaults to None
:type extra_headers: Optional[Dict[str, Optional[str]]], optional
"""
if extra_headers is None:
extra_headers = {}
query_params_map: Dict[str, str] = prepare_params(
{
'min_height': to_string(min_height),
'min_width': to_string(min_width),
'max_height': to_string(max_height),
'max_width': to_string(max_width),
}
)
headers_map: Dict[str, str] = prepare_params({**extra_headers})
response: FetchResponse = fetch(
FetchOptions(
url=''.join(
[
self.network_session.base_urls.base_url,
'/2.0/files/',
to_string(file_id),
'/thumbnail.',
to_string(extension),
]
),
method='GET',
params=query_params_map,
headers=headers_map,
response_format=ResponseFormat.NO_CONTENT,
auth=self.auth,
network_session=self.network_session,
follow_redirects=False,
)
)
if response.headers['location'] == None:
raise BoxSDKError(message='No location header in response')
return response.headers['location']

def get_file_thumbnail_by_id(
self,
file_id: str,
Expand Down
6 changes: 6 additions & 0 deletions box_sdk_gen/networking/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class APIRequest:
headers: Dict[str, str]
params: Dict[str, str]
data: Optional[Union[str, ByteStream, MultipartEncoder]]
allow_redirects: bool = True


@dataclass
Expand Down Expand Up @@ -95,6 +96,7 @@ def fetch(options: FetchOptions) -> FetchResponse:
):
if options.response_format == 'binary':
return FetchResponse(
url=network_response.url,
status=network_response.status_code,
headers=dict(response.network_response.headers),
content=ResponseByteStream(
Expand All @@ -103,6 +105,7 @@ def fetch(options: FetchOptions) -> FetchResponse:
)
else:
return FetchResponse(
url=network_response.url,
status=network_response.status_code,
headers=dict(response.network_response.headers),
data=(
Expand Down Expand Up @@ -149,6 +152,7 @@ def __prepare_request(
headers = __prepare_headers(options, reauthenticate)
params = options.params or {}
data = __prepare_body(options.content_type, options.file_stream or options.data)
allow_redirects = options.follow_redirects

if options.content_type:
if options.content_type == 'multipart/form-data':
Expand All @@ -175,6 +179,7 @@ def __prepare_request(
headers=headers,
params=params,
data=data,
allow_redirects=allow_redirects,
)


Expand Down Expand Up @@ -226,6 +231,7 @@ def __make_request(request: APIRequest, session: Session) -> APIResponse:
headers=request.headers,
data=request.data,
params=request.params,
allow_redirects=request.allow_redirects,
stream=True,
)
reauthentication_needed = (
Expand Down
6 changes: 5 additions & 1 deletion box_sdk_gen/networking/fetch_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ def __init__(
content_type: str = 'application/json',
response_format: ResponseFormat = ResponseFormat.JSON,
auth: Optional[Authentication] = None,
network_session: Optional[NetworkSession] = None
network_session: Optional[NetworkSession] = None,
follow_redirects: Optional[bool] = True
):
"""
:param url: URL of the request
Expand All @@ -89,6 +90,8 @@ def __init__(
:type auth: Optional[Authentication], optional
:param network_session: Network session object, defaults to None
:type network_session: Optional[NetworkSession], optional
:param follow_redirects: A boolean value indicate if the request should follow redirects. Defaults to True. Not supported in Browser environment., defaults to True
:type follow_redirects: Optional[bool], optional
"""
self.url = url
self.method = method
Expand All @@ -101,3 +104,4 @@ def __init__(
self.response_format = response_format
self.auth = auth
self.network_session = network_session
self.follow_redirects = follow_redirects
4 changes: 4 additions & 0 deletions box_sdk_gen/networking/fetch_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def __init__(
status: int,
headers: Dict[str, str],
*,
url: Optional[str] = None,
data: Optional[SerializedData] = None,
content: Optional[ByteStream] = None
):
Expand All @@ -21,12 +22,15 @@ def __init__(
:type status: int
:param headers: HTTP headers of the response
:type headers: Dict[str, str]
:param url: URL of the response, defaults to None
:type url: Optional[str], optional
:param data: Response body of the response, defaults to None
:type data: Optional[SerializedData], optional
:param content: Streamed content of the response, defaults to None
:type content: Optional[ByteStream], optional
"""
self.status = status
self.headers = headers
self.url = url
self.data = data
self.content = content
47 changes: 47 additions & 0 deletions docs/downloads.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,55 @@
# DownloadsManager

- [Download file URL](#download-file-url)
- [Download file](#download-file)
- [Download file](#download-file)

## Download file URL

Get the download URL without downloading the content.

This operation is performed by calling function `get_download_file_url`.

See the endpoint docs at
[API Reference](https://developer.box.com/reference/get-files-id-content/).

<!-- sample get_files_id_content -->

```python
client.downloads.get_download_file_url(uploaded_file.id)
```

### Arguments

- file_id `str`
- The unique identifier that represents a file. The ID for any file can be determined by visiting a file in the web application and copying the ID from the URL. For example, for the URL `https://*.app.box.com/files/123` the `file_id` is `123`. Example: "12345"
- version `Optional[str]`
- The file version to download
- access_token `Optional[str]`
- An optional access token that can be used to pre-authenticate this request, which means that a download link can be shared with a browser or a third party service without them needing to know how to handle the authentication. When using this parameter, please make sure that the access token is sufficiently scoped down to only allow read access to that file and no other files or folders.
- range `Optional[str]`
- The byte range of the content to download. The format `bytes={start_byte}-{end_byte}` can be used to specify what section of the file to download.
- boxapi `Optional[str]`
- The URL, and optional password, for the shared link of this item. This header can be used to access items that have not been explicitly shared with a user. Use the format `shared_link=[link]` or if a password is required then use `shared_link=[link]&shared_link_password=[password]`. This header can be used on the file or folder shared, as well as on any files or folders nested within the item.
- extra_headers `Optional[Dict[str, Optional[str]]]`
- Extra headers that will be included in the HTTP request.

### Returns

This function returns a value of type `str`.

Returns the requested file if the client has the **follow
redirects** setting enabled to automatically
follow HTTP `3xx` responses as redirects. If not, the request
will return `302` instead.
For details, see
the [download file guide](g://downloads/file#download-url).If the file is not ready to be downloaded yet `Retry-After` header will
be returned indicating the time in seconds after which the file will
be available for the client to download.

This response can occur when the file was uploaded immediately before the
download request.

## Download file

Returns the contents of a file in binary format.
Expand Down
Loading

0 comments on commit fd609ab

Please sign in to comment.