Skip to content

Commit

Permalink
Merge a886524 into 567ea52
Browse files Browse the repository at this point in the history
  • Loading branch information
carycheng committed Oct 4, 2018
2 parents 567ea52 + a886524 commit d4c5af0
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 0 deletions.
12 changes: 12 additions & 0 deletions boxsdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..util.api_call_decorator import api_call
from ..object.search import Search
from ..object.events import Events
from ..object.trash import Trash
from ..pagination.limit_offset_based_object_collection import LimitOffsetBasedObjectCollection
from ..pagination.marker_based_object_collection import MarkerBasedObjectCollection
from ..util.shared_link import get_shared_link_header
Expand Down Expand Up @@ -159,6 +160,17 @@ def collaboration(self, collab_id):
"""
return self.translator.translate('collaboration')(session=self._session, object_id=collab_id)

def trash(self):
"""
Initialize a :class:`Trash` object.
:return:
A :class:`Trash` object.
:rtype:
:class:`Trash`
"""
return Trash(self._session)

def legal_hold_policy(self, policy_id):
"""
Initialize a :class:`LegalHoldPolicy` object, whose box id is policy_id.
Expand Down
1 change: 1 addition & 0 deletions boxsdk/object/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
'retention_policy',
'retention_policy_assignment',
'search',
'trash',
'task',
'task_assignment',
'user',
Expand Down
120 changes: 120 additions & 0 deletions boxsdk/object/trash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# coding: utf-8
from __future__ import unicode_literals, absolute_import

import json

from .base_endpoint import BaseEndpoint
from ..pagination.limit_offset_based_object_collection import LimitOffsetBasedObjectCollection


class Trash(BaseEndpoint):
"""Box API endpoint for performing trash related actions in Box."""

def get_from_trash(self, item, fields=None):
"""
Get item from trash.
:param item:
The :class:`File` or :class:`Folder` or :class:`WebLink` object to restore from trash.
:type item:
:class:`File` or :class:`Folder` or :class:`WebLink`.
:param fields:
List of fields to request
:type fields:
`Iterable` of `unicode`
:returns:
A trashed :class:`File`, :class:`Folder`, or :class:`WebLink` object.
:rtype:
:class:`File`, :class:`Folder`, or :class:`WebLink`
"""
url = self._session.get_url(item.object_type + 's', item.object_id, 'trash')
params = {}
if fields:
params['fields'] = ','.join(fields)
box_response = self._session.get(url, params=params)
response = box_response.json()
return self.translator.translate(response['type'])(
session=self._session,
object_id=response['id'],
response_object=response,
)

def restore_from_trash(self, item, name=None, parent_id=None, fields=None):
"""
Restores an item from the trash. Could be files, folders, or weblinks.
:param item:
The :class:`File` or :class:`Folder` or :class:`WebLink` object to restore from trash.
:type item:
:class:`File` or :class:`Folder` or :class:`WebLink`.
:param name:
The new name for this item. Only used if the item can't be restored due to name conflict.
:type name:
`unicode` or None
:param parent_id:
The id of the new parent folder. Only used if the previous parent folder no longer exists.
:type parent_id:
`unicode` or None
:param fields:
List of fields to request
:type fields:
`Iterable` of `unicode`
:returns:
A restored :class:`File`, :class:`Folder`, or :class:`WebLink`.
:rtype:
:class:`File`, :class:`Folder`, or :class:`WebLink`.
"""
url = self._session.get_url(item.object_type + 's', item.object_id)
body = {}
if name is not None:
body['name'] = name
if parent_id is not None:
body['parent'] = {'id': parent_id}
params = {}
if fields:
params['fields'] = ','.join(fields)
box_response = self._session.post(url, data=json.dumps(body), params=params)
response = box_response.json()
return self.translator.translate(response['type'])(
session=self._session,
object_id=response['id'],
response_object=response,
)

def permanently_delete_item(self, item):
"""
Permanently delete an item that is in the trash. The item will no longer exist in Box.
"""
url = self._session.get_url(item.object_type + 's', item.object_id, 'trash')
box_response = self._session.delete(url, expect_json_response=False)
return box_response.ok

def get_trashed_items(self, limit=None, offset=None, fields=None):
"""
Using limit-offset paging, get the files, folders and web links that are in the user's trash.
:param limit:
The maximum number of entries to return per page. If not specified, then will use the server-side default.
:type limit:
`int` or None
:param offset:
The offset of the item at which to begin the response.
:type offset:
`int` or None
:param fields:
List of fields to request.
:type fields:
`Iterable` of `unicode`
:returns:
An iterator of the entries in the trash
:rtype:
:class:`BoxObjectCollection`
"""
return LimitOffsetBasedObjectCollection(
session=self._session,
url=self._session.get_url('folders', 'trash', 'items'),
limit=limit,
offset=offset,
fields=fields,
return_full_pages=False,
)
97 changes: 97 additions & 0 deletions docs/trash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
Trash
=====

Under normal circumstances, when an item in Box is deleted, it is not actually erased immediately. Instead, it is
moved to the Trash. The Trash allows you to recover files and folders that have been deleted. By default, items in
the Trash will be purged after 30 days.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [List Trashed Items](#list-trashed-items)
- [Get Trashed File, Folder or WebLink](#get-trashed-file-folder-or-weblink)
- [Restore File, Folder, or WebLink from Trash](#restore-file-folder-or-weblink-from-trash)
- [Permanently Delete File, Folder or WebLink](#permanently-delete-file-folder-or-weblink)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

List Trashed Items
------------------

To retrieve a list of all trashed items, you can use `client.trash().get_trashed_items(offset=None, limit=None, fields=None)`

```python
trashed_items = client.trash().get_trashed_items()
for trashed_item in trashed_items:
# Do something
```

Get Trashed File, Folder or WebLink
-----------------------------------

To retrieve a file, folder, weblink from the trash, use `client.trash.get_from_trash(item, fields=None)`.

```python
file = client.file('11111')
file_from_trash = client.trash().get_from_trash(file)
```

```python
folder = client.folder('22222')
folder_from_trash = client.trash().get_from_trash(folder)
```

```python
web_link = client.web_link('33333')
web_link_from_Trash = client.trash().get_from_trash(web_link)
```

Restore File, Folder, or WebLink from Trash
-------------------------------------------

To retore a trashed item, effectively undeleting it, call `client.trash().restore_from_trash(item, name=None, parent_id=None, fields=None)`.

```python
file_to_restore = client.file('11111')
restored_file = client.trash().restore_from_trash(file_to_restore)
```

```python
folder_to_restore = client.folder('22222')
restored_folder = client.trash().restore_from_trash(folder_to_restore)
```

```python
web_link_to_restore = client.web_link('33333')
restored_web_link = client.trash().restore_from_trash(web_link_to_restore)
```

In order to avoid conflicts, you can set a new name and new parent folder for the item you wish to restore.

```python
file = client.file('11111')
new_name = 'New File Name'
new_parent_id = '1111'
restored_file = client.trash().restore_from_trash(file, new_name, new_parent_id)
```

Permanently Delete File, Folder or WebLink
-------------------------------------------

To delete an item from trash, use `client.trash().permanently_delete_item(item)`.

```python
file = client.file('11111')
client.trash().permanently_delete_item(file)
```

```python
folder = client.folder('22222')
client.trash().permanently_delete_item(folder)
```

```python
web_link = client.web_link('33333')
client.trash().permanently_delete_item(web_link)
```
6 changes: 6 additions & 0 deletions test/unit/client/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from boxsdk.object.file import File
from boxsdk.object.group import Group
from boxsdk.object.user import User
from boxsdk.object.trash import Trash
from boxsdk.object.group_membership import GroupMembership
from boxsdk.object.retention_policy import RetentionPolicy
from boxsdk.object.file_version_retention import FileVersionRetention
Expand Down Expand Up @@ -495,6 +496,11 @@ def test_legal_hold_policies_return_the_correct_policy_objects(
assert policy._session == mock_box_session


def test_trash_initializer(mock_client):
trash = mock_client.trash()
assert isinstance(trash, Trash)


def test_get_recent_items_returns_the_correct_items(mock_client, mock_box_session, recent_items_response, file_id):
mock_box_session.get.return_value = recent_items_response
recent_items = mock_client.get_recent_items()
Expand Down
9 changes: 9 additions & 0 deletions test/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,12 @@ def mock_folder_response(mock_object_id, make_mock_box_request):
response={'type': 'folder', 'id': mock_object_id},
)
return mock_box_response


@pytest.fixture(scope='function')
def mock_web_link_response(mock_object_id, make_mock_box_request):
# pylint:disable=redefined-outer-name
mock_box_response, _ = make_mock_box_request(
response={'type': 'web_link', 'id': mock_object_id},
)
return mock_box_response

0 comments on commit d4c5af0

Please sign in to comment.