Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
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
1 change: 1 addition & 0 deletions 1 HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Next Release
**New Features and Enhancements:**

- Add metadata query functionality (`#574 <https://github.com/box/box-python-sdk/pull/574>`_)
- Add folder lock functionality (`#581 <https://github.com/box/box-python-sdk/pull/581>`_)

2.11.0 (2021-01-11)
++++++++
Expand Down
15 changes: 15 additions & 0 deletions 15 boxsdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1733,3 +1733,18 @@ def download_zip(self, name, items, writeable_stream):
session=self._session,
response_object=status,
)

def folder_lock(self, folder_lock_id):
"""
Initialize a :class:`FolderLock` object, whose box id is folder_lock_id.

:param folder_lock_id:
The ID of the :class:`FolderLock` object.
:type folder_lock_id:
`unicode`
:return:
A :class:`FolderLock` object with the given entry ID.
:rtype:
:class:`FolderLock`
"""
return self.translator.get('folder_lock')(session=self._session, object_id=folder_lock_id)
49 changes: 49 additions & 0 deletions 49 boxsdk/object/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,3 +677,52 @@ def cascade_metadata(self, metadata_template):

response = self._session.post(url, data=json.dumps(body)).json()
return self.translator.translate(self._session, response)

@api_call
def create_lock(self):
"""
Creates a folder lock on a folder, preventing it from being moved and/or deleted.

:returns:
The created folder lock
:rtype:
:class:`FolderLock`
"""
url = self._session.get_url('folder_locks')

body = {
'folder': {
'type': 'folder',
'id': self.object_id
},
'locked_operations': {
'move': True,
'delete': True
}
}

response = self._session.post(url, data=json.dumps(body)).json()
return self.translator.translate(self._session, response)

@api_call
def get_locks(self):
"""
Lists all folder locks for a given folder.

:returns:
The collection of locks for a folder.
:rtype:
:class:`BoxObjectCollection`
"""
url = self._session.get_url('folder_locks')

additional_params = {
'folder_id': self.object_id,
sujaygarlanka marked this conversation as resolved.
Show resolved Hide resolved
}

return MarkerBasedObjectCollection(
url=url,
session=self._session,
additional_params=additional_params,
return_full_pages=False,
)
9 changes: 9 additions & 0 deletions 9 boxsdk/object/folder_lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# coding: utf-8
from __future__ import unicode_literals
from .base_object import BaseObject


class FolderLock(BaseObject):
"""Represents the folder lock"""

_item_type = 'folder_lock'
43 changes: 43 additions & 0 deletions 43 docs/usage/folders.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,3 +463,46 @@ client.folder(folder_id='11111').remove_classification()
```

[remove_classification]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.item.Item.remove_classification

Create a Folder Lock
-------------

To lock a folder, call
[`client.folders(folder_id).create_lock()`][create-folder-lock]
with the ID of the folder. This prevents the folder from being moved and/or deleted.

```python
lock = client.folders(folder_id).create_lock()
print('Created a lock with ID {0}'.format(lock.folder.id))
```

[create_folder_lock]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder.Folder.create_lock


Get Folder Locks
-------------------------

To retrieve a list of the locks on a folder, call
[`client.folders(folder_id).get_locks()][get-folder-locks]
with the ID of the folder. Currently only one lock can exist per folder. Folder locks define access restrictions placed by folder owners to prevent specific folders from being moved or deleted.

```python
locks = client.folders(folder_id).get_locks()
lock = locks.next()
print('A lock on a folder with ID {0}'.format(lock.folder.id))
```

[get_folder_locks]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder.Folder.get_locks

Delete a Folder Lock
------------------

To remove a folder lock, call
[`client.folder_lock(folder_lock_id).delete()`][delete-folder-lock]
with the ID of the folder lock.

```python
client.folder_lock(folder_lock_id='22222').delete()
```

[delete_folder_lock]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder_lock.FolderLock
6 changes: 6 additions & 0 deletions 6 test/unit/object/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from boxsdk.object.file_version_retention import FileVersionRetention
from boxsdk.object.legal_hold import LegalHold
from boxsdk.object.folder import Folder
from boxsdk.object.folder_lock import FolderLock
from boxsdk.object.group import Group
from boxsdk.object.group_membership import GroupMembership
from boxsdk.object.legal_hold_policy import LegalHoldPolicy
Expand Down Expand Up @@ -374,3 +375,8 @@ def test_metadata_template(mock_box_session):
'templateKey': 'vContract',
}
return MetadataTemplate(mock_box_session, None, fake_response)


@pytest.fixture()
def test_folder_lock(mock_box_session, mock_object_id):
return FolderLock(mock_box_session, mock_object_id)
98 changes: 97 additions & 1 deletion 98 test/unit/object/test_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
# pylint:disable=protected-access
# pylint:disable=redefined-outer-name


@pytest.fixture()
def mock_new_upload_accelerator_url():
return 'https://upload.box.com/api/2.0/files/content?upload_session_id=123'
Expand Down Expand Up @@ -562,3 +561,100 @@ def test_cascade_metadata(test_folder, mock_box_session, test_metadata_template)
assert folder.object_id == test_folder.object_id
assert cascade_policy.scope == test_metadata_template.scope
assert cascade_policy.templateKey == test_metadata_template.template_key


def test_get_folder_locks(test_folder, mock_box_session):
expected_url = '{0}/folder_locks'.format(API.BASE_API_URL)
params = {'folder_id': test_folder.object_id}
mock_box_session.get.return_value.json.return_value = {
"entries": [
{
"folder": {
"id": "12345",
"etag": "1",
"type": "folder",
"sequence_id": "3",
"name": "Contracts"
},
"id": "12345678",
"type": "folder_lock",
"created_by": {
"id": "11446498",
"type": "user"
},
"created_at": "2020-09-14T23:12:53Z",
"locked_operations": {
"move": True,
"delete": True
},
"lock_type": "freeze"
}
],
"limit": 1000,
"next_marker": None
}

folder_locks = test_folder.get_locks()
lock = folder_locks.next()

mock_box_session.get.assert_called_once_with(expected_url, params=params)
assert lock.id == '12345678'
assert lock.folder.id == '12345'
assert lock.locked_operations['move']
# pylint: disable=protected-access
assert lock._session == mock_box_session


def test_create_folder_lock(test_folder, mock_box_session):
expected_url = '{0}/folder_locks'.format(API.BASE_API_URL)
expected_body = {
"folder": {
"type": "folder",
"id": test_folder.object_id
},
"locked_operations": {
"move": True,
"delete": True
}
}
mock_box_session.post.return_value.json.return_value = {
"id": "12345678",
"type": "folder_lock",
"created_at": "2020-09-14T23:12:53Z",
"created_by": {
"id": "11446498",
"type": "user"
},
"folder": {
"id": "12345",
"type": "folder",
"etag": "1",
"name": "Contracts",
"sequence_id": "3"
},
"lock_type": "freeze",
"locked_operations": {
"delete": True,
"move": True
}
}

lock = test_folder.create_lock()

mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_body))
assert lock.id == '12345678'
assert lock.folder.id == '12345'
assert lock.locked_operations['move']
# pylint: disable=protected-access
assert lock._session == mock_box_session


def test_delete_folder_lock(test_folder_lock, mock_box_session):
expected_url = '{0}/folder_locks/{1}'.format(API.BASE_API_URL, test_folder_lock.object_id)
test_folder_lock.delete()
mock_box_session.delete.assert_called_once_with(
expected_url,
expect_json_response=False,
headers=None,
params={}
)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.