Skip to content

Commit 2794f86

Browse files
Add folder lock functionality (#581)
1 parent d6d6fcf commit 2794f86

File tree

7 files changed

+220
-1
lines changed

7 files changed

+220
-1
lines changed

HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Next Release
99
**New Features and Enhancements:**
1010

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

1314
2.11.0 (2021-01-11)
1415
++++++++

boxsdk/client/client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,3 +1733,18 @@ def download_zip(self, name, items, writeable_stream):
17331733
session=self._session,
17341734
response_object=status,
17351735
)
1736+
1737+
def folder_lock(self, folder_lock_id):
1738+
"""
1739+
Initialize a :class:`FolderLock` object, whose box id is folder_lock_id.
1740+
1741+
:param folder_lock_id:
1742+
The ID of the :class:`FolderLock` object.
1743+
:type folder_lock_id:
1744+
`unicode`
1745+
:return:
1746+
A :class:`FolderLock` object with the given entry ID.
1747+
:rtype:
1748+
:class:`FolderLock`
1749+
"""
1750+
return self.translator.get('folder_lock')(session=self._session, object_id=folder_lock_id)

boxsdk/object/folder.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,52 @@ def cascade_metadata(self, metadata_template):
677677

678678
response = self._session.post(url, data=json.dumps(body)).json()
679679
return self.translator.translate(self._session, response)
680+
681+
@api_call
682+
def create_lock(self):
683+
"""
684+
Creates a folder lock on a folder, preventing it from being moved and/or deleted.
685+
686+
:returns:
687+
The created folder lock
688+
:rtype:
689+
:class:`FolderLock`
690+
"""
691+
url = self._session.get_url('folder_locks')
692+
693+
body = {
694+
'folder': {
695+
'type': 'folder',
696+
'id': self.object_id
697+
},
698+
'locked_operations': {
699+
'move': True,
700+
'delete': True
701+
}
702+
}
703+
704+
response = self._session.post(url, data=json.dumps(body)).json()
705+
return self.translator.translate(self._session, response)
706+
707+
@api_call
708+
def get_locks(self):
709+
"""
710+
Lists all folder locks for a given folder.
711+
712+
:returns:
713+
The collection of locks for a folder.
714+
:rtype:
715+
:class:`BoxObjectCollection`
716+
"""
717+
url = self._session.get_url('folder_locks')
718+
719+
additional_params = {
720+
'folder_id': self.object_id,
721+
}
722+
723+
return MarkerBasedObjectCollection(
724+
url=url,
725+
session=self._session,
726+
additional_params=additional_params,
727+
return_full_pages=False,
728+
)

boxsdk/object/folder_lock.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# coding: utf-8
2+
from __future__ import unicode_literals
3+
from .base_object import BaseObject
4+
5+
6+
class FolderLock(BaseObject):
7+
"""Represents the folder lock"""
8+
9+
_item_type = 'folder_lock'

docs/usage/folders.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,46 @@ client.folder(folder_id='11111').remove_classification()
463463
```
464464

465465
[remove_classification]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.item.Item.remove_classification
466+
467+
Create a Folder Lock
468+
-------------
469+
470+
To lock a folder, call
471+
[`client.folders(folder_id).create_lock()`][create-folder-lock]
472+
with the ID of the folder. This prevents the folder from being moved and/or deleted.
473+
474+
```python
475+
lock = client.folders(folder_id).create_lock()
476+
print('Created a lock with ID {0}'.format(lock.folder.id))
477+
```
478+
479+
[create_folder_lock]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder.Folder.create_lock
480+
481+
482+
Get Folder Locks
483+
-------------------------
484+
485+
To retrieve a list of the locks on a folder, call
486+
[`client.folders(folder_id).get_locks()][get-folder-locks]
487+
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.
488+
489+
```python
490+
locks = client.folders(folder_id).get_locks()
491+
lock = locks.next()
492+
print('A lock on a folder with ID {0}'.format(lock.folder.id))
493+
```
494+
495+
[get_folder_locks]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder.Folder.get_locks
496+
497+
Delete a Folder Lock
498+
------------------
499+
500+
To remove a folder lock, call
501+
[`client.folder_lock(folder_lock_id).delete()`][delete-folder-lock]
502+
with the ID of the folder lock.
503+
504+
```python
505+
client.folder_lock(folder_lock_id='22222').delete()
506+
```
507+
508+
[delete_folder_lock]: https://box-python-sdk.readthedocs.io/en/latest/boxsdk.object.html#boxsdk.object.folder_lock.FolderLock

test/unit/object/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from boxsdk.object.file_version_retention import FileVersionRetention
1414
from boxsdk.object.legal_hold import LegalHold
1515
from boxsdk.object.folder import Folder
16+
from boxsdk.object.folder_lock import FolderLock
1617
from boxsdk.object.group import Group
1718
from boxsdk.object.group_membership import GroupMembership
1819
from boxsdk.object.legal_hold_policy import LegalHoldPolicy
@@ -374,3 +375,8 @@ def test_metadata_template(mock_box_session):
374375
'templateKey': 'vContract',
375376
}
376377
return MetadataTemplate(mock_box_session, None, fake_response)
378+
379+
380+
@pytest.fixture()
381+
def test_folder_lock(mock_box_session, mock_object_id):
382+
return FolderLock(mock_box_session, mock_object_id)

test/unit/object/test_folder.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
# pylint:disable=protected-access
2525
# pylint:disable=redefined-outer-name
2626

27-
2827
@pytest.fixture()
2928
def mock_new_upload_accelerator_url():
3029
return 'https://upload.box.com/api/2.0/files/content?upload_session_id=123'
@@ -562,3 +561,100 @@ def test_cascade_metadata(test_folder, mock_box_session, test_metadata_template)
562561
assert folder.object_id == test_folder.object_id
563562
assert cascade_policy.scope == test_metadata_template.scope
564563
assert cascade_policy.templateKey == test_metadata_template.template_key
564+
565+
566+
def test_get_folder_locks(test_folder, mock_box_session):
567+
expected_url = '{0}/folder_locks'.format(API.BASE_API_URL)
568+
params = {'folder_id': test_folder.object_id}
569+
mock_box_session.get.return_value.json.return_value = {
570+
"entries": [
571+
{
572+
"folder": {
573+
"id": "12345",
574+
"etag": "1",
575+
"type": "folder",
576+
"sequence_id": "3",
577+
"name": "Contracts"
578+
},
579+
"id": "12345678",
580+
"type": "folder_lock",
581+
"created_by": {
582+
"id": "11446498",
583+
"type": "user"
584+
},
585+
"created_at": "2020-09-14T23:12:53Z",
586+
"locked_operations": {
587+
"move": True,
588+
"delete": True
589+
},
590+
"lock_type": "freeze"
591+
}
592+
],
593+
"limit": 1000,
594+
"next_marker": None
595+
}
596+
597+
folder_locks = test_folder.get_locks()
598+
lock = folder_locks.next()
599+
600+
mock_box_session.get.assert_called_once_with(expected_url, params=params)
601+
assert lock.id == '12345678'
602+
assert lock.folder.id == '12345'
603+
assert lock.locked_operations['move']
604+
# pylint: disable=protected-access
605+
assert lock._session == mock_box_session
606+
607+
608+
def test_create_folder_lock(test_folder, mock_box_session):
609+
expected_url = '{0}/folder_locks'.format(API.BASE_API_URL)
610+
expected_body = {
611+
"folder": {
612+
"type": "folder",
613+
"id": test_folder.object_id
614+
},
615+
"locked_operations": {
616+
"move": True,
617+
"delete": True
618+
}
619+
}
620+
mock_box_session.post.return_value.json.return_value = {
621+
"id": "12345678",
622+
"type": "folder_lock",
623+
"created_at": "2020-09-14T23:12:53Z",
624+
"created_by": {
625+
"id": "11446498",
626+
"type": "user"
627+
},
628+
"folder": {
629+
"id": "12345",
630+
"type": "folder",
631+
"etag": "1",
632+
"name": "Contracts",
633+
"sequence_id": "3"
634+
},
635+
"lock_type": "freeze",
636+
"locked_operations": {
637+
"delete": True,
638+
"move": True
639+
}
640+
}
641+
642+
lock = test_folder.create_lock()
643+
644+
mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_body))
645+
assert lock.id == '12345678'
646+
assert lock.folder.id == '12345'
647+
assert lock.locked_operations['move']
648+
# pylint: disable=protected-access
649+
assert lock._session == mock_box_session
650+
651+
652+
def test_delete_folder_lock(test_folder_lock, mock_box_session):
653+
expected_url = '{0}/folder_locks/{1}'.format(API.BASE_API_URL, test_folder_lock.object_id)
654+
test_folder_lock.delete()
655+
mock_box_session.delete.assert_called_once_with(
656+
expected_url,
657+
expect_json_response=False,
658+
headers=None,
659+
params={}
660+
)

0 commit comments

Comments
 (0)